"? extends ParentClass" 使只读?

Posted

技术标签:

【中文标题】"? extends ParentClass" 使只读?【英文标题】:"? extends ParentClass" makes Read only? 【发布时间】:2015-12-13 09:13:51 【问题描述】:

在下面的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。我找不到确切的原因。

【问题讨论】:

我不知道,注意 nums.add((Number) new Double(3.14));导致错误: List 不适用于参数 (Number) 看到这个问题:***.com/questions/2723397/java-generics-what-is-pecs 这是一个很常见的误解;但这个概念在大多数情况下都有效:) 更多了解请参考docs.oracle.com/javase/tutorial/java/generics/bounded.html 【参考方案1】:

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

不...因为该代码不知道它“实际上”是什么列表。想象一下,如果你可以

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 这样的通配符时,您只能输入值in 通过 API - 因为那是安全的。

【讨论】:

@PradipKharbuja:不,不是真的。该列表本身不是只读的——您仍然可以通过ints 添加到它,或者通过nums 从它中删除。由于类型安全,您不能添加nums【参考方案2】:

不,它不是只读的……尽管这通常是意图。

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

由于get() 返回X,我们也可以使用来自get() 的值调用add() .... 直接调用list.add(list.get(i)) 是行不通的,尽管它是有意义的。我们需要一点helper。

经典的例子是Collections.reverse(List&lt;? extends Object&gt; list)。此方法将修改list,尽管有通配符。

当然,您也可以在任何列表上调用像 clear() 这样的变异方法。


话虽如此,通配符确实主要用于使用站点variance,并且大多数情况下,它传达了API设计人员的意图,即类型参数是用于in还是出来。例如,通过声明 List&lt;? super/extends Foo&gt;,API 表示它打算将 T 注入,或者,将 T 从列表中取出

通配符使只读/只写是一种误解。但这种误解适用于大多数用例。而且越多的人有这种误解,它就越会成为一种惯例……

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

【讨论】:

【参考方案3】:

当您将List&lt;? extends Number&gt; nums 视为扩展Number 的某种类型的事物的List 时,这很有帮助,但您无法确定是什么。因此,您对nums 所做的所有事情都需要能够完成这样的事情。

添加null 有效,因为null 可以转换成任何东西。您尝试添加的所有其他内容都将失败,因为编译器无法 100% 确定您添加的内容扩展了列表的内容。

List&lt;Number&gt; nums代替List&lt;? extends Number&gt; nums,因为你仍然可以放入任何扩展Number的东西。

? 不是“任何东西”的意思,它更接近于“一些特定但未知的”的意思。

【讨论】:

【参考方案4】:

泛型只是编译时间。

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

List<? extends Number>

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

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

【讨论】:

以上是关于"? extends ParentClass" 使只读?的主要内容,如果未能解决你的问题,请参考以下文章

% extends "base.html" % 和 % block content % 在 if 语句中(Django 应用程序)

"? extends ParentClass" 使只读?

221 jQuery 拷贝对象:$.extend()

[React] Create component variations in React with styled-components and "extend"

如何在快递应用程序中设置基于翡翠的选项? (“basedir”选项需要使用“extends”和“absolute”路径)

解决 IDEA 下 struts.xml 中 extends="struts-default" 报红的问题