&#34 ;?扩展ParentClass"制作只读?

时间:2015-09-16 16:53:21

标签: java generics null generic-list readonly-collection

在下面的代码Java中,我创建了一个列表nums。我可以在声明期间分配另一个列表。但是除了null之外,无法添加新项目。那么,这是否意味着nums是只读的? 为什么?是否可以在该列表中添加新项目?

List<Integer> ints = new ArrayList<Integer>();
ints.add(1);
ints.add(2);

List<? extends Number> nums = ints;
nums.add(3.14); //Generates error
nums.addAll(ints);  //Generates error

nums.add(null);     //works
System.out.println(nums.get(0));    //works

我已经完成了这个link。我无法得到确切的理由。

4 个答案:

答案 0 :(得分:6)

  

是否可以在该列表中添加新项目?

没有......因为该代码并不知道它的实际情况&#34;的列表。想象一下,如果你可以

List<String> strings = new ArrayList<>();
List<? extends Object> objects = strings; // This is fine
objects.add(new Object()); // Fortunately this *isn't* valid...
System.out.println(strings.get(0).length()); // Or what would this do?

基本上,当您使用像? extends T这样的通配符时,您只能通过API获取值 out ...当您使用? super T之类的通配符时,您可以只能通过API将值放在中 - 因为这样做是安全的。

答案 1 :(得分:2)

不,它不是只读的......即使这通常是意图。

给定一个List<? extends Number>对象,编译器converts的类型为List<X>,其中X是Number的未知子类型。因此,该对象确实具有add(X)方法。我们可以使用X参数调用该方法...例如,null

由于get()返回X,我们也可以使用add()中的值来调用get() ....直接调用list.add(list.get(i))将无法正常工作,即使它有意义。我们需要一点helper

经典的例子是Collections.reverse(List<? extends Object> list)。尽管使用了通配符,此方法仍将修改list

当然,您也可以在任何列表中调用clear()等变异方法。

话虽如此,通配符确实主要用于使用网站variance,并且大多数情况下,它传达了API设计者的意图,即类型参数是否适用于 或者 out 。例如,通过声明List<? super/extends Foo>,API表示它打算将T插入,或者中获取T,列表。

通配符使读/写成为一种误解。但是这种误解在大多数用例中起作用。这种误解的人越多,它就越成为一种惯例......

请参阅我关于通配符的文章 - http://bayou.io/draft/Capturing_Wildcards.html

答案 2 :(得分:0)

当您将List<? extends Number> nums视为List延伸Number的某种类型的事物时,它会有所帮助,但您无法确定是什么。因此,您使用nums所做的一切都需要能够做到这一点。

添加null有效,因为null可以投射到任何内容中。您尝试添加的其他所有内容都将失败,因为编译器无法100%确定您添加的内容会扩展列表所构成的内容。

而不是List<? extends Number> nums执行List<Number> nums,因为您仍然可以放入任何扩展Number的内容。

?并不意味着&#34;任何事情&#34;,它更接近于意义&#34;某些具体但未知的&#34;。

答案 3 :(得分:-1)

泛型只是编译时间。

因此编译器将决定我们将要使用的实际类型。

List<? extends Number>

这意味着我们不确定该对象的实际类型。

因此编译器无法确定列表的实际类型是什么。