泛型方法上的多個通配符:Java 編譯器難題
簡介
Java 泛型中、通配符(*)代表未知型別。當在泛型方法上使用多個通配符時,可能會導致混亂和意外行為。本文探討了多個通配符的複雜性及其對 Java 類型安全性的影響。
混亂
考慮以下程式碼:
public class TwoListsOfUnknowns { static void doNothing(List<?> list1, List<?> list2) { } public static void main(String[] args) { List<String> list1 = null; List<Integer> list2 = null; doNothing(list1, list2); // compiles fine! } }
doNothing 中的兩個通配符看起來不相關,允許您使用List
static void doSomethingIllegal(List<?> list1, List<?> list2) { list1.addAll(list2); // DOES NOT COMPILE!!! }
這表明雖然 list1 和 list2 可以是不同的類型,但它們可能存在某種連接,無法直接使用。
嵌套通配符的混亂
進一步調查發現,混亂不在於多個通配符,而在於嵌套通配符:
public class LOLUnknowns1 { static void probablyIllegal(List<List<?>> lol, List<?> list) { lol.add(list); // this compiles!! how come??? } }
即使list 可能是與lol 元素不同的類型,此程式碼編譯也不會出現錯誤。但是,需要注意的是,這種情況會引發有關類型安全的問題。
真相:捕獲轉換
這種混亂源自於稱為捕獲轉換的概念。它允許某些通配符在泛型方法中使用時捕獲特定類型。這就是為什麼下面的 possibleIllegal 變體可以編譯:
static void probablyIllegalAgain(List<List<? extends Number>> lol, List<? extends Number> list) { lol.add(list); // compiles fine!!! how come??? }
這裡,lol 中的通配符可以捕獲擴展 Number 的類型,例如 List
理解嵌套通配符
關鍵要點是多個通配符本身沒有問題。當嘗試使用嵌套通配符捕獲由於類型差異而不“相容”的類型時,會出現混亂。
對於 LOLUnknowns1,List> 中的巢狀通配符是無法捕獲特定類型,因為捕獲對於 lol 的所有可能元素類型來說並不安全。這就是為什麼 list 可以是任何類型,從而導致潛在的類型安全問題。
結論
泛型方法上的多個通配符可能會令人困惑,但了解捕獲轉換和它的局限性至關重要。嵌套通配符需要仔細考慮以確保類型安全。透過遵守這些原則,您可以了解 Java 泛型的複雜性並編寫健全的程式碼。
以上是為什麼 Java 中泛型方法上的多個通配符會導致混亂?的詳細內容。更多資訊請關注PHP中文網其他相關文章!