2015-05-10 60 views
2

采取以下代码:约泛型奇怪的行为,我

public class Main { 

    public static void main(String[] args) { 
     List<Object> list1 = new ArrayList<Object>(); 
     List<? super Integer> list2 = list1; 
     list2.add(1); 
     list1.add("two"); 
     //list2.add("three"); // will never compile!!. 
     System.out.println("list1: " + list1.toString()); 
     System.out.println("list2: " + list2.toString()); 

    } 

} 

这里是输出:

list1: [1, two] 
list2: [1, two] 

,一方面,列表2不允许在对象的add()方法像弦“三”;但另一方面,它引用一个包含对象的列表。

+2

你能澄清一下实际问题是什么吗?我假设它是这样的:“当list2的类型是'?super Integer'时,list2似乎包含一个字符串(在print语句中),特别是给它添加一个字符串为list2.add(”three“) '不会编译?“但你真正给出的只是一个观察。 – alexroussos

+0

你拥有的是一个有效的赋值列表,如果你不考虑它被处理的序列,那么这个赋值可能看起来很奇怪。在你指定'list2 = list1'时,它是完全有效的,即使在稍后的点你可以通过'list1.add(“three”)添加新条目(因为它们实际上是一个单独的列表);'没有什么奇怪和不寻常的关于它 –

回答

3

编译器不关心列表实例接受哪种对象。在字节码级,任何参考因类型擦除而被接受。它只知道使用特定泛型类型参数化的List类型的两个变量。这些变量之一可以分配给另一个是被检查然后被遗忘的东西。

因此,当您尝试添加"three"时,它会查看list2类型所接受的泛型类型,看到它不匹配并引发编译错误。

至于方案:没有任何问题。如果要通过变量引用来限制要添加或从列表中删除的对象,则由您决定。

请注意,无法从变量引用的列表中检索String而无法进行转换。

+0

我同意认为这种事情是*远*从直觉上讲,我不是当前设置与泛型方面的大粉丝。 –

+0

你能解释为什么'list2.add(new Object());'不能编译,因为'Object'显然是'Integer'的超类型?你不应该能够添加任何超级类型,而只需要_get_一个'Integer'而不需要投射? –

+0

我只能通过[参考另一个问题](http://stackoverflow.com/q/3847162/589259)来解释这一点。它有点相同,但没有从'list1'到'list2'的分配。如上所述,这对我来说也不直观。 –