2020/07/31

[筆記] Effective Java #26 請不要使用原生類型

Effective Java 3rd 簡體中文版筆記 #26 請不要使用原生類型
當某個 class 或介面中,定義一個或多個類型參數 (type parameter),那就是泛型 (generic) 的 class 或介面。像是 List 就有定義 E 作為類型變數,定義泛型的參數會用 <> 來表示,List<String> 就表示元素類型為 String,當 List 使用時沒有定義 E,稱作該 List原生類型 (raw type)。以下列程式碼為例,如果 names 列表使用原生類型,若有開發者誤將整數 7 新增到 names 中,編譯時並不會有問題,會到執行時才會發現,但如果有定義 <String>,編譯時就會發生錯誤。
// java.util.List
public interface List<E> extends Collection<E> { ... }

// raw type
List names = new ArrayList();
names.add("Allen");
names.add(7);
使用原生類型是合法的,但不應該這麼使用。如果使用原生類型,就失去泛型在安全性和描述性方面的優勢。那為什麼要允許這樣使用? 維持兼容性,在泛型推出前,已有大量使用原生類型的程式碼存在,須對既存的程式碼提供支援。那 ListList<Object> 有什麼區別? 前者逃避泛型檢查,後者有明確定義,List<String> 無法轉換成 List<Object>,但可以轉成 List。那無限制類型的 Set<?> 與 Set 有什麼區別? Set 可以新增任何類型的元素,容易破壞原有的類型約束,若為 Set<?> 是無法新增任何非 null 的元素。
List<String> names = new ArrayList<>();
names.add("Allen");
List<?> list = names;
list.add(null);
list.add("Billy");  // can not compile!
那麼何時會需要使用原生類型呢? 使用類文字(class literal)instanceof 時,像是 List.classString[].class,但 List<String>.classList<?>.class 是不合法的。因為泛型在運行時資訊是消去的,所以在使用 instanceof 時,是無法使用 List<String> 來比較的,在比較時使用原生類型,但轉換時應使用 wildcard 類型。
if (o instanceof Set) { // Raw type
    Set<?> s = (Set<?>) o; // Wildcard type
    ...
}
Class literal
https://stackoverflow.com/questions/2160788/what-is-a-class-literal-in-java
轉載請註明原文網址 https://cookieandcoketw.blogspot.com/2020/07/effective-java-26-raw-type.html

沒有留言:

張貼留言