Java 泛型程序設計
1. 泛型類
public class Pair<T> { private T first; private T second; public void setSecond(T second){...} .... }
2. 泛型方法
class ArrAlg{ public static <T> T getMiddle(T... a){ return a[a.length/2]; } }
3. 類型變量的限定
public static <T extends BoundingType1 & BoundingType2 ...> T min(T[] a)....
這表示T應該是BoundingType類型的子類型。T和綁定類型可以是類,也可以是接口 。一個類型變量或通配符可以有多個限定,但限定中之多隻有一個類,這是因為單繼承,當有多個限定時,基類要寫在第一個,接口寫在後面。
4. 原始類型,任何一個泛型類型,都自動提供一個原始類型,原始類型的名字就是刪去類型參數後的類型名。例如Pair<T>, 原始類型就是Pair。
5. 泛型轉換
- 虛擬機中沒有泛型,只有普通的類和方法
- 所有的類型參數都用它們的第一個限定類型替換,沒有寫明限定類型就用Object
- 合成橋方法保持多態。
- 為保持類型安全性,必要時插入強制類型轉換(例如調用泛型方法返回值)
5. 橋方法
假設有下列類繼承了Pair<Date>,
class DateInterval extends Pair<Date> { public void setSecond(Date second){ .... } }
實際擦除類型之後
class DateInterval extends Pair { public void setSecond(Date second){...} //因為類型擦除,實際還存在一個繼承於Pair類的方法,顯然這是兩個方法 public void setSecond(Object second){ //實際生成橋方法,這裏會調用setSecond(Date seconde);即: setSecond((Date)second); } }
當如下調用時 Pair<Date> pair = new DateInterval(...); pair.setSecond(aDate);
。Pair類型只有一個方法setSecond(Object)。實際引用DateInterval類,因而將會調用DateInterval.setSecond(Object)。編譯器為了調用最合適的方法,實際上生成了一個橋方法,如下 public void setSecond(Object second){ setSecond((Date) second) }
。
6. 約束與侷限性
- 不能用基本類型實例化類型參數
- 運行時類型查詢只適用於原始類型
-
不能創建參數化類型的數組,即不能
new Pair<String> [10]
- 不能實例化類型變量,即不能使用 new T(...), new T[] 或T.class這類的表達式。可以通過反射實例化T但不能T.class.newInstance(); 可以如下設計API來實現。
public static <T> Pair<T> makePair(Class<T> cl){ try{ return new Pair<>(cl.newInstance(), cl.newInstance()) }catch(Exception e){return null;} }
-
泛型類的靜態上下文中不能引用類型變量,例如
private static T aData; 或者 public static T fun(){}都是錯誤的。
- 不能拋出或捕獲泛型類的實例
7. 通配符
- 通配符限定: extends 、super
例:Pair<? extends Person>表示泛型Pair類型,它的參數是Person的子類。
在這種情況下,getter和setter區別,getter可以正常調用,但是setter不行,會產生編譯錯誤,因為編譯器不能確定要傳入參數的類型,也沒法代替。
?extends Person getFirst() void setFirst(? extends Person)
反之,通配符的超類型限定: ?super Student
void setFirst(? super Student); ? super Student getFirst();
編譯器雖然不知道setFirst的確切類型,但是可以用任意Student對象調用,而不能用Person對象調用。如果調用getFirst,返回的對象不能保證,只能賦給Object。
- 無限定通配符 Pair<?>
? getFirst(); void setFirst(?);
getFirst的返回值只能賦給一個Object, setFirst不能調用除非setFirst(null),對於一些簡單操作非常有用,例如判定是否為null getFirst() == null
- 通配符捕獲 可以通過泛型方法捕獲通配符
- 記一次批量更新整型類型的列 → 探究 UPDATE 的使用細節
- 編碼中的Adapter,不僅是一種設計模式,更是一種架構理念與解決方案
- 線程池底層原理詳解與源碼分析
- 30分鐘掌握 Webpack
- 線性迴歸大結局(嶺(Ridge)、 Lasso迴歸原理、公式推導),你想要的這裏都有
- Django 之路由層
- 【前端必會】webpack loader 到底是什麼
- day42-反射01
- 中心化決議管理——雲端分析
- HashMap底層原理及jdk1.8源碼解讀
- 詳解JS中 call 方法的實現
- 打印 Logger 日誌時,需不需要再封裝一下工具類?
- 初識設計模式 - 代理模式
- 設計模式---享元模式
- 密碼學奇妙之旅、01 CFB密文反饋模式、AES標準、Golang代碼
- [ML從入門到入門] 支持向量機:從SVM的推導過程到SMO的收斂性討論
- 從應用訪問Pod元數據-DownwardApi的應用
- Springboot之 Mybatis 多數據源實現
- Java 泛型程序設計
- CAS核心思想、底層實現