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]");
为什么我们收到编译时错误?
答案 0 :(得分:1)
这是因为java泛型中的类型擦除。
您无法向list添加新元素,因为它的类型参数在编译时未定义。
列表List<? extends Number> nums
表示您无法在其上调用add方法。
答案 1 :(得分: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)
不是整数,所以它会抛出异常。最好在编译时捕获这些问题。
答案 2 :(得分:0)
我认为这里的重要部分是实例化(new ArrayList<Integer>()
),它明确地将Integer
传递给List类。左手边的钻石符号并不重要,只要它兼容即可。由于您后来将泛型定义为Integer
的上边界,主要是Number
及其子类型,因此Java可以处理它,因为它仍然可以处理整数。该对象基本上仍然是List<Integer>
。
这就像将一个String赋给一个Object。它会起作用,因为Object
是String
的超类型。这里List<? extends Number>
有点像List<Integer>
的超类型。 (我知道“超级型”这个词在这里是不正确的,所以请随意纠正我。)
使用泛型的实例化有点像类本身和对象的实例化。其他一些语言,例如Python正在使用术语“元类”来表达这种行为。