所以我正在查看一些Java代码并偶然发现:
List<? extends SomeObject> l;
基本上这个列表接受某些SomeObject - SomeObject本身或其继承者的所有对象。但是根据多态性,它的继承者也可以像SomeObject一样,所以这也可以工作:
List<SomeObject> l;
那么,为什么有人会在第二个选项明确定义并且几乎相同时使用第一个选项?
答案 0 :(得分:30)
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>;
中你无法在列表中添加任何内容,因为?代表未知类(除了课程除外)。
更新:在评论What could I possibly do with a list if I cannot add anything to it?
现在考虑一种情况,你必须编写一个函数来打印你的列表,但请注意,它必须只接受一个具有SomeObject 子类的对象的List。在这种情况下,如上所述,你不能使用
public void printList(List<SubClassOfSomeObjectClass> someList)
那你会怎么做?你会做类似
的事情 public void printList(List<? extends SomeObject> someList) {
for(SomeObject myObj : someList) {
//process read operations on myObj
}
答案 1 :(得分:4)
您要阅读的关键链接是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>
,在这种情况下,用户无法将他拥有的字符串列表传递给您的方法,如果您接受Collection<? extends Object>
,则用户可以传递他的Collection<Apple>, Collection<Orange>
等,而无需显式创建另一个清单。
答案 2 :(得分:2)
List<? extends SomeObject> l;
不接受new SomeObject()
但List<SomeObject> l;
确实如此。
什么也行不通:
List<SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
工作原理:
List<? extends SomeObject> l = new ArrayList<SubTypeOfSomeObject>()
答案 3 :(得分:0)
X
可以转换为List<Y>
, X
也无法添加到Y
。
所以,在你的第二种情况下,如果允许List<X> l;
添加X的子类,那将破坏类型安全的基本原则
答案 4 :(得分:-2)
作为第一个答案,
List<? extends SomeObject> l;
必须包含从SomeObject继承的Object,而不是某些直接的SomeObject。