[英]Generics - Why don't some versions work?
此代码取自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");
}
您需要问的是编译器是否可以确定 list
的元素类型是否与String
一致:
<?>
- 类型未知。 例如,它可能是Integer
。 我们不知道String
适合。 new List<Integer>().add("quack")
不会编译,所以这也不能。 <? extends Object>
<? extends Object>
- 再次,类型未知。 所有类都扩展了Object
。 所以它也可能是Integer
。 <Object>
- 这里没有泛型。 String
是Object
的子类。 new List<Object>().add("quack")
有效,所以这个编译。 <? super String>
<? 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>
<? super FilterInputStream>
匹配Object
, InputStream
, FilterInputStream
, Closeable
和AutoCloseable
。
List<? super FilterInputStream> l
List<? super FilterInputStream> l
可以是List<Closeable>
,也可以是List<InputStream
>等等。但是你所知道的是你可以l.add(new FilterInputStream())
或者,因为它是l.add(new BufferedInputStream())
的子类l.add(new BufferedInputStream())
在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也不起作用。 有关通用边界,请参阅此答案
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.