2017-04-11 82 views
1
List<Integer> ints = new ArrayList<Integer>(); 
ints.add(1); ints.add(2); 
List<? extends Number> nums = ints; 
nums.add(3.14); // compile-time error 
assertints.toString().equals("[1, 2, 3.14]"); 

为什么我们要编译时错误?java通配符中的泛型

+0

请参阅:http://stackoverflow.com/questions/5495383/java-generics-wildcard-question-list-extends-a?rq=1 –

+0

另请参阅:http://stackoverflow.com/a/6439506/2928853 – jrook

回答

1

这是因为Java泛型中的类型擦除。 您不能将新元素添加到列表中,因为它的类型参数在编译时未定义。 列表List<? extends Number> nums意味着你不能调用add方法。

1

List<? extends Number>意味着我们不知道列表中的类型是什么,除非它是Number

在这种情况下,它是一个List<Integer>。即使将其分配给List<? extends Number>,它基本上仍然是List<Integer>。你不能将3.14添加到这样的列表。

如果被允许,下面的代码是有效的:

List<Integer> ints = new ArrayList<Integer>(); 
ints.add(1); ints.add(2); 
List<? extends Number> nums = ints; 
nums.add(3.14); 
Integer third = ints.get(2); 

ints.get(2)不是整数,所以它会在这里抛出异常。在编译时更好地捕捉这些类型的问题。

+0

我认为'nums'不知何故仍然是一个整数列表是有点不准确。不仅你不能添加浮动,你甚至不能将整数添加到'nums'列表中。 'nums.add(new Integer(1))'仍然不能编译。 – jrook

+0

同意@jrook ...在错误发生的地方,编译器只知道'nums'是一个'List <?扩展Number>'。它没有跟踪可能已经分配到“nums”中的内容。因此,基于nums是一个Integer列表,你不能得到一个编译时错误。这种错误可能会在运行时被捕获,尽管在这种情况下它可能不会因为类型擦除而被捕获。 – ajb

0

我认为这里的重要部分是实例化(new ArrayList<Integer>()),它明确地将Integer传递给List类。只要兼容,左手菱形符号并不重要。由于您稍后将泛型定义为Integer的上边界,主要是Number及其子类型,因此Java仍然可以处理整数。该对象本质上仍然是一个List<Integer>

这就像给一个对象分配一个字符串。它将工作,因为ObjectString的超类型。这里的List<? extends Number>有点像超类型List<Integer>。 (我知道单词“超类型”在这里是不正确的,所以请随时纠正我。)

泛型的实例有点像类本身和对象的实例化。其他一些语言,例如Python对这种行为使用术语“元类”。

+0

我见过使用“超类”,所以如果“超类”错了,那还不算错。 – ajb