此代码取自OCP教科书。为什么addSound方法的版本1和版本2不能编译,但版本3和版本4编译?编译错误消息是" List中的add(capture)无法应用于java.lang.String"
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
strings.add("tweet");
List<Object> objects = new ArrayList<>(strings);
addSound(strings);
addSound(objects);
}
//version 1
public static void addSound(List<?> list) {
list.add("quack");
}
//version 2
public static void addSound(List<? extends Object> list) {
list.add("quack");
}
//version 3
public static void addSound(List<Object> list) {
list.add("quack");
}
//version 4
public static void addSound(List<? super String> list) {
list.add("quack");
}
答案 0 :(得分:3)
您需要问的是,编译器是否某些 list
的元素类型与String
一致:
<?>
- 类型未知。例如,它可能是Integer
。我们无法知道String
适合。 new List<Integer>().add("quack")
无法编译,因此也不能编译。 <? extends Object>
- 再次,类型未知。所有课程都延伸Object
。所以它可能是Integer
。<Object>
- 此处没有仿制药。 String
是Object
的子类。 new List<Object>().add("quack")
有效,因此编译。<? super String>
这是未知的,条件(“ bounds ”)表明它是String
的超类。由于我们知道String extends Object
,因此此类型只能是Object
或String
。 List<Object>().add("quack")
没问题,List<String>().add("quack")
没问题,所以编译。第4号的推理当然适用于更复杂的类型层次结构:
BufferedInputStream
延伸FilterInputStream
延伸InputStream
延伸Object
。 InputStream
实现了接口Closeable
和AutoCloseable
。
所以<? super FilterInputStream>
匹配Object
,InputStream
,FilterInputStream
,Closeable
和AutoCloseable
。
所以List<? super FilterInputStream> l
可以是List<Closeable>
,也可以是List<InputStream
&gt;等等。但您确定知道的是l.add(new FilterInputStream())
或者,因为它是一个子类l.add(new BufferedInputStream())
答案 1 :(得分:2)
在Java中,您有类型安全和类型擦除。这两个概念都是版本1和版本2不起作用的原因。
您无法向List<?>
添加任何内容,因为您不知道列表中的对象类型。例如,它可能是Integer
或String
的列表。
public static void addSound(List<?> list) {
list.add("quack"); // does not work since List<?> can be anything - type safety not guaranteed
}
Java编译器在运行时删除所有类型,称为类型擦除,例如List<String>
将List
而List<Integer>
也将List
- 因此您无法区分它们。您可能会在字节码中看到它,但这与此无关。这就是版本2无法正常工作的原因
//version 2 - has the same type erasure as version 3
public static void addSound(List<? extends Object> list) {
list.add("quack");
}
//version 3
public static void addSound(List<Object> list) {
list.add("quack");
}
由于类型安全性,版本2也无法正常工作。请参阅generic bounds
的答案