0

考虑以下代码:

MyClass myClass= new MyExtendedClass();
myClass.method();

其中 MyExtendedClass 是 MyClass 的子类型。正如我在第二个字符串编译器上的编译状态编译器上所理解的那样,它检查method()了源代码中的存在方法MyClass。是正确的推理吗?现在考虑

List<Integer> ints= new ArrayList<Integer>();
ints.add(2);
List<? extends Integer> lst = ints;
lst.get(0);

我在哪里可以看到的来源List<? extends Integer>?现在考虑:

new ArrayList<Integer>().getClass().equals(
    new ArrayList<String>().getClass());// return true.

所以在运行时类ArrayList<Integer>ArrayList<String>是相等的,但在编译状态下它是不正确的。为什么?ArrayList<String>和的来源在哪里ArrayList<Integer>

4

3 回答 3

1

搜索类型擦除。要开始,您可以参考http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

于 2013-09-25T16:36:35.367 回答
0

Java 不像 C++ 那样工作。在 C++ 中,“模板”会导致完整生成具有该引用类型的新类。然而,Java 不会为每个模板化实例生成一个新类。相反,类型信息在编译和运行时作为设置携带。所以 ArrayList<Integer> 和 ArrayList<String> 使用相同的实际类。

类型检查在编译器中,对于简单的类来说这很容易。

class Gem {...}
class Ruby extends Gem {...}
class Diamond extends Gem {...}

Gem a;
Ruby b;
Diamond c;

a = b;   //no problem allowed
b = a;   //type problem, need to cast it!
b = c;   //never allowed!

但是参数化的类要复杂得多

List<Gem> la;
List<Ruby> lb;
List<Diamond> lc;

la = lb;   //not allowed because type is different even though Ruby extends Gem

List<? extends Gem> ld;

ld = la;  //allowed
ld = lb;  //also allowed
ld = lc;  //also allowed

需要通配符以允许您拥有一个包含多种集合的集合变量,其中不同之处在于类型参数。在所有情况下,对象类(和源代码)都保持不变。

于 2013-09-25T16:41:25.217 回答
0

为了myClass.method();合法,MyClass类或接口必须声明method方法。那是对的。

getClass结果相等ArrayList<Integer>的原因ArrayList<String>是,在运行时,类型擦除会擦除泛型类型参数,ArrayList在两种情况下都留下,当然它们都是相等的。只有编译器才能区分ArrayList<Integer>ArrayList<String>。JVM 从来不知道泛型,所以类型擦除恰好与泛型前(Java 1.5 前)应用程序向后兼容。

于 2013-09-25T16:38:24.580 回答