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通配符中的泛型
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通配符中的泛型
这是因为Java泛型中的类型擦除。 您不能将新元素添加到列表中,因为它的类型参数在编译时未定义。 列表List<? extends Number> nums
意味着你不能调用add方法。
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)
不是整数,所以它会在这里抛出异常。在编译时更好地捕捉这些类型的问题。
我认为这里的重要部分是实例化(new ArrayList<Integer>()
),它明确地将Integer
传递给List类。只要兼容,左手菱形符号并不重要。由于您稍后将泛型定义为Integer
的上边界,主要是Number
及其子类型,因此Java仍然可以处理整数。该对象本质上仍然是一个List<Integer>
。
这就像给一个对象分配一个字符串。它将工作,因为Object
是String
的超类型。这里的List<? extends Number>
有点像超类型List<Integer>
。 (我知道单词“超类型”在这里是不正确的,所以请随时纠正我。)
泛型的实例有点像类本身和对象的实例化。其他一些语言,例如Python对这种行为使用术语“元类”。
我见过使用“超类”,所以如果“超类”错了,那还不算错。 – ajb
请参阅:http://stackoverflow.com/questions/5495383/java-generics-wildcard-question-list-extends-a?rq=1 –
另请参阅:http://stackoverflow.com/a/6439506/2928853 – jrook