方法调用和通配符

时间:2013-09-25 16:33:34

标签: java generics arraylist wildcard

请考虑以下代码:

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>的来源在哪里?

3 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

要使myClass.method();合法,MyClass类或接口必须声明method方法。这是对的。

getClass结果与ArrayList<Integer>ArrayList<String>相等的原因是,在运行时,类型擦除会删除泛型类型参数,在这两种情况下都会留下ArrayList,当然,他们都是平等的。只有编译器才能区分ArrayList<Integer>ArrayList<String>。 JVM从未了解泛型,因此类型擦除与预先泛型(Java 1.5之前的版本)应用程序向后兼容。

答案 2 :(得分:0)

Java不像C ++那样工作。在C ++中,“模板”导致完整生成具有该引用类型的新类。但是,Java不会为每个模板化实例化生成新类。相反,类型信息在编译和运行时作为设置进行。所以ArrayList&lt; Integer&gt;和ArrayList&lt; String&gt;使用相同的实际课程。

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

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

需要使用通配符来允许您拥有一个包含多种集合的集合变量,其中差异在type参数中。在所有情况下,对象类(和源代码)保持不变。