所以我正在查看一些Java代码并偶然发现:
List<? extends SomeObject> l;
基本上,这个列表接受所有属于某种 SomeObject 的对象 - SomeObject 本身或其继承者。但是根据多态性,它的继承者也可以被视为 SomeObject,所以这也可以:
List<SomeObject> l;
那么,当第二个选项被明确定义并且几乎相同时,为什么有人会使用第一个选项呢?
所以我正在查看一些Java代码并偶然发现:
List<? extends SomeObject> l;
基本上,这个列表接受所有属于某种 SomeObject 的对象 - SomeObject 本身或其继承者。但是根据多态性,它的继承者也可以被视为 SomeObject,所以这也可以:
List<SomeObject> l;
那么,当第二个选项被明确定义并且几乎相同时,为什么有人会使用第一个选项呢?
List<SomeObject> l;
在这你不能说List<SomeObject> l = new ArrayList<SubClassOfSomeObjectClass>;
(不允许)在哪里
List<? extends SomeObject> l;
你可以说
List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>;
(允许)
但请注意,List<? extends SomeObject> l = new ArrayList<SubClassOfSomeObject>;
您不能在列表中添加任何内容 l因为 ? 表示未知类(当然 null 除外)。
更新: 对于您在评论中的问题What could I possibly do with a list if I cannot add anything to it?
现在考虑一种情况,您必须编写一个函数来打印您的列表,但请注意,它必须只接受一个包含对象的 List,这些对象是您的 SomeObject 的子类。在这种情况下,如上所述,您不能使用
public void printList(List<SubClassOfSomeObjectClass> someList)
那你会怎么做?你会做类似的事情
public void printList(List<? extends SomeObject> someList) {
for(SomeObject myObj : someList) {
//process read operations on myObj
}
您要阅读的关键链接是http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html,它详细解释了通用通配符。
不List<SomeObject>
一样。List<? extends SomeObject>
请注意以下事项
List<Object> x = new ArrayList<Object>();
List<String> y = new ArrayList<String>();
// x = y; Will throw Compilation exception
List<? extends Object> z = y; //will pass compilation
您可能希望观察到您可以在 x 和 y 列表中添加一个字符串,但是当您编写一个库函数(例如链接中显示的示例中的 printCollection)而不是接受一个Collection<Object>
in在这种情况下,用户无法将他拥有的字符串列表传递给您的方法,如果您接受,Collection<? extends Object>
则用户可以传递他的Collection<Apple>, Collection<Orange>
等,而无需显式创建另一个列表。
List<? extends SomeObject> l;
不接受new SomeObject()
,但接受List<SomeObject> l;
。
什么也不起作用:
List<SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
什么工作:
List<? extends SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
X
List<Y>
即使X
可以转换为也无法添加Y
。
所以,在你的第二种情况下,如果List<X> l;
允许添加 X 的子类,那将破坏类型安全的基本原则
作为第一个答案,
List<? extends SomeObject> l;
必须包含从 SomeObject 继承的 Object,而不是直接 SomeObject。