簡體   English   中英

泛型 - 為什么某些版本不起作用?

[英]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一致:

  1. <?> - 類型未知。 例如,它可能是Integer 我們不知道String適合。 new List<Integer>().add("quack")不會編譯,所以這也不能。
  2. <? extends Object> <? extends Object> - 再次,類型未知。 所有類都擴展了Object 所以它也可能是Integer
  3. <Object> - 這里沒有泛型。 StringObject的子類。 new List<Object>().add("quack")有效,所以這個編譯。
  4. <? super String> <? super String>這是未知的,條件(“ bounds ”)表示它是String的超類。 由於我們知道String extends Object ,因此這種類型只能是ObjectString List<Object>().add("quack")List<String>().add("quack") ,所以這個編譯。

數字4的推理當然適用於更復雜的類型層次結構:

BufferedInputStream擴展FilterInputStream擴展InputStream擴展Object InputStream實現了CloseableAutoCloseable接口。

那么<? super FilterInputStream> <? super FilterInputStream>匹配ObjectInputStreamFilterInputStreamCloseableAutoCloseable

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<?>添加任何內容,因為您不知道列表中的對象類型。 例如,它可能是IntegerString的列表。

public static void addSound(List<?> list) {
    list.add("quack"); // does not work since List<?> can be anything - type safety not guaranteed
}

Java編譯器在運行時刪除所有類型,稱為類型擦除,例如List<String>將是ListList<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM