[英]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.