Given:
import java.util.*;
public class Hancock {
//insert code here
list.add("foo");
}
}
哪两个代码片段独立插入到第 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) {
正确答案是 B 和 C。
答案A和B对我来说非常清楚。对于答案 C 和 D,我知道继承的方向,但是我无法理解为什么答案 D 不能在 Eclipse 中编译,而所有其他答案都可以(A 带有关于泛型的警告,B 和 C 没有警告)。
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>();
}
为什么?为什么<? super String>
不在方法声明中编译,而在变量声明中编译。
我知道String
是最后一堂课,不能由任何其他课程扩展,但这并不能向我解释这里发生的事情。
首先我们来看答案C:
public void addString(List<? super String> list) {
list.add("foo");
}
该方法声明表示您将被允许通过List
由某个超类参数化的对象String
, 例如String
or Object
. So:
- 如果你通过了
List<String>
the list.add("foo")
将完全有效。
- 如果你通过了
List<Object>
the list.add("foo")
将是完全有效的,因为“foo”是String
(并且您可以添加String
to a List<Object>
).
这意味着答案C是正确的。
现在我们来看答案D。
如果你有这样的方法声明:
public void addString(List<? extends String> list) {
}
这意味着您将能够通过List
参数化的对象一些未知的的亚型String
。所以,当你这样做时list.add("foo");
编译器不会知道提供的对象是否具有与unknown的亚型String
因此会引发编译时错误。
当你有:
public void addString() {
List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
}
这个片段编译得很好,因为list1
被定义为持有List
属于某些未知子类型的对象String
, 包括String
本身,这就是它有效的原因。
问题是你将无法添加任何内容, 除了null
.
As for list2
,变量可以保存List
由某些超类型参数化的对象String
, 包括String
itself.
更多信息:
- 什么是 PESC? https://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
- Java通配符中super和extends有什么区别? https://stackoverflow.com/questions/4343202/difference-between-super-t-and-extends-t-in-java
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)