Dáv*_*áve 10 java generics collections extends super
鉴于:
import java.util.*;
public class Hancock {
//insert code here
list.add("foo");
}
}
Run Code Online (Sandbox Code Playgroud)
在第5行独立插入的哪两个代码片段将在没有警告的情况下编译?(选择两个)
A. public void addString(List list) {
B. public void addString(List<String> list) {
C. public void addString(List<? super String> list) {
D. public void addString(List<? extends String> list) {
Run Code Online (Sandbox Code Playgroud)
正确答案是B&C.
答案A和B对我来说非常清楚.对于答案C&D我知道继承的方式,但是我无法理解为什么答案D不能在Eclipse中编译,而所有其他人都这样做(A有关于通用的警告,B&C没有warrings).
Eclipse中答案D的错误是The method add(capture#1-of ? extends String) in the type List<capture#1-of ? extends String> is not applicable for the arguments (String)
.
另一方面,这编译:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
Run Code Online (Sandbox Code Playgroud)
为什么?为什么<? super String>
在变量声明中编译时不在方法声明中编译.
我知道这String
是最后一堂课,不能被任何其他班级扩展,但这并没有向我解释这里发生了什么.
首先,让我们看看答案C:
public void addString(List<? super String> list) {
list.add("foo");
}
Run Code Online (Sandbox Code Playgroud)
此方法声明表示您将被允许传递List
由某些超类参数化的对象String
,例如String
或Object
.所以:
List<String>
的list.add("foo")
将是完全有效的.List<Object>
的list.add("foo")
将是完全有效的,因为"富"是String
(你可以添加String
到 List<Object>
).这意味着答案C是正确的.
现在让我们看看答案D.
如果您有这样的方法声明:
public void addString(List<? extends String> list) {
}
Run Code Online (Sandbox Code Playgroud)
这意味着您将能够传递List
由某个未知子类型参数化的对象String
.因此,当您执行list.add("foo");
此操作时,编译器将不会知道所提供的对象是否具有与未知子类型匹配的类型,String
因此会引发编译时错误.
当你有:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
Run Code Online (Sandbox Code Playgroud)
这个片段编译得很好,因为它list1
被定义为List
包含某些未知子类型的对象String
,包括它String
自身,这就是它有效的原因.问题是你将无法添加任何东西,除了null
.
至于list2
,变量可以保存List
由某些超类型(String
包括其String
自身)参数化的对象.
更多信息: