摘要:java 泛型轉(zhuǎn)換的事實:虛擬機中沒有泛型, 只有普通的類和方法: 因為存在 類型擦除, 泛型類型被替換為限定類型(無限定類型就使用 Object), 限定類型是指 <T extends ClassName & InterfaceName & XXX>;所有的類型參數(shù)都用它們的限定類型替換;
java 泛型轉(zhuǎn)換的事實:
虛擬機中沒有泛型, 只有普通的類和方法: 因為存在 類型擦除, 泛型類型被替換為限定類型(無限定類型就使用 Object), 限定類型是指
<T extends ClassName & InterfaceName & XXX>;
所有的類型參數(shù)都用它們的限定類型替換;
編譯器會生成 橋方法 以保持多態(tài);
為保持類型安全性, 必要時插入強制類型轉(zhuǎn)換;
java 泛型的約束和局限性:
1. 不能使用基本類型實例化類型參數(shù);
2. 運行時類型查詢只適用于原始類型;
因為 類型擦除, java 虛擬機中的對象沒有泛型類型這一說, instanceof 和 getClass() 只能查詢到原始類型, 具體的泛型類型時無從得知的.
3. 不能創(chuàng)建參數(shù)化類型的數(shù)組
只可聲明參數(shù)化類型的數(shù)組, 但不能創(chuàng)建參數(shù)化類型的數(shù)組.
例如 Pair<String> table = new Pair<String>[10] 是錯誤的,
4. Varargs 警告
雖然不支持創(chuàng)建泛型類型的數(shù)組, 但由于可變參數(shù)其實是個數(shù)組, 當向可變參數(shù)化傳遞泛型類型時, 就會有這個問題.
為此 java 編譯器支持了這種情況, 但還會產(chǎn)生一個警告, 可通過 @SafeVarargs 注解抑制該警告.
5. 不能實例化類型變量
不能直接通過 new 實例化類型變量(因為 類型擦除 后會變成 Object 類型), 這時候可借助函數(shù)式接口 Supplier<T>,
表示一個無參數(shù)且返回類型為 T 的函數(shù):
public static <T> Pair<T> makePair<Supplier<T> constr) { return new Pair<>(constr.get(), constr.get()); } Pair<String> pair = Pair.makePair(String.class);
6. 不能構(gòu)造泛型數(shù)組
7. 泛型類的靜態(tài)上下文類型變量無效
8. 不能拋出或捕獲泛型類的實例
9. 可以消除對受查異常的檢測
10. 注意類型擦除后的沖突
要想支持擦除的轉(zhuǎn)換, 就需要強行限制一個類或類型變量不能同時成為兩個接口類型的子類, 而這兩個接口是同一接口的不同參數(shù)化. 例如下述代碼是非法的:
class Employee implements Comparable<Employee> { ... } class Manager extends Employee implements Comparable<Manager> { ... }
Manager 會實現(xiàn) Comparable<Employee> 和 Comparable<Manager>, 這是同一接口的不同參數(shù)化.
但, 非泛型版本是合法的:
class Employee implements Comparable { ... } class Manager extends Employee implements Comparable { ... }
泛型里的通配符概念
當知道泛型的具體類型時, 使用字符 T(當然其他字符也行).
但當泛型的參數(shù)類型變化時, 就只能使用 ? 了. 其中:
<? extends 類或接口>: 子類型限定, 只可從泛型對象讀取, 不能寫入;
<? super 類或接口>: 超類型限定, 可向泛型對象寫入, 讀取時不能保證類型(只能是 Object).