"? 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是否可以在该列表中添加新项目?
不...因为该代码不知道它“实际上”是什么列表。想象一下,如果你可以:
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<? extends Number>
对象,编译器converts 的类型为List<X>
,其中X 是Number 的未知子类型。因此,该对象确实有一个add(X)
方法。我们可以使用X
参数调用该方法……例如,null
。
由于get()
返回X
,我们也可以使用来自get()
的值调用add()
.... 直接调用list.add(list.get(i))
是行不通的,尽管它是有意义的。我们需要一点helper。
经典的例子是Collections.reverse(List<? extends Object> list)
。此方法将修改list
,尽管有通配符。
当然,您也可以在任何列表上调用像 clear()
这样的变异方法。
话虽如此,通配符确实主要用于使用站点variance,并且大多数情况下,它传达了API设计人员的意图,即类型参数是用于in还是出来。例如,通过声明 List<? super/extends Foo>
,API 表示它打算将 T 注入,或者,将 T 从列表中取出。
通配符使只读/只写是一种误解。但这种误解适用于大多数用例。而且越多的人有这种误解,它就越会成为一种惯例……
请参阅我关于通配符的文章 - http://bayou.io/draft/Capturing_Wildcards.html
【讨论】:
【参考方案3】:当您将List<? extends Number> nums
视为扩展Number
的某种类型的事物的List
时,这很有帮助,但您无法确定是什么。因此,您对nums
所做的所有事情都需要能够完成这样的事情。
添加null
有效,因为null
可以转换成任何东西。您尝试添加的所有其他内容都将失败,因为编译器无法 100% 确定您添加的内容扩展了列表的内容。
用List<Number> nums
代替List<? extends Number> nums
,因为你仍然可以放入任何扩展Number
的东西。
?
不是“任何东西”的意思,它更接近于“一些特定但未知的”的意思。
【讨论】:
【参考方案4】:泛型只是编译时间。
所以编译器将决定我们要使用的实际类型。
List<? extends Number>
这意味着我们不确定对象的实际类型。
所以编译器无法确定列表的实际类型是什么。
【讨论】:
以上是关于"? extends ParentClass" 使只读?的主要内容,如果未能解决你的问题,请参考以下文章
% extends "base.html" % 和 % block content % 在 if 语句中(Django 应用程序)
[React] Create component variations in React with styled-components and "extend"
如何在快递应用程序中设置基于翡翠的选项? (“basedir”选项需要使用“extends”和“absolute”路径)