基礎程式設計(Java)· CH20
為何用泛型 · 泛型方法 · 泛型類別 · 有界型別 · 多型別參數 · 萬用字元 · 導覽地圖
完整內容看 PDF 講義,型別替換互動與試跑看 index。
全章主線
ClassCastException
有泛型 <T>兩大好處:編譯期型別安全+免手動轉型。
泛型方法
public static <T> void printArray(T[] a) {
for (T e : a) System.out.print(e + " "); // 方法內用 T
}
printArray(ints); // T 自動推斷為 Integer
printArray(words); // T 自動推斷為 String
<T> 放在 static 之後、回傳型別之前。一份方法取代多個只有型別不同的多載。
泛型類別
public class Box<T> {
private T value; // 欄位型別是 T
public T get() { return value; }
}
Box<Integer> bi = new Box<>(42); // 菱形 <> 推斷
int n = bi.get(); // 不必轉型
填不同型別實參,編譯器把 T 替換成具體型別。static 方法用不到類別的 T。
型別實參
Box<Integer> ok; // 參考型別(包裝類別)
// Box<int> bad; // ← 編譯錯:基本型別不能當型別實參
型別參數=定義時的佔位符 T;型別實參=使用時填的 Integer。型別實參必須是參考型別(自動裝箱幫忙在 int/Integer 間轉換)。
有界型別參數
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b; // 有界才能呼叫 compareTo
}
沒上界時 T 只當 Object,呼叫不到 compareTo。上界=extends 後那個型別;泛型一律寫 extends(涵蓋類別與介面)。
多型別參數
public class Pair<K, V> {
private K key;
private V value;
}
Pair<String, Integer> p = new Pair<>("age", 18);
逗號分隔、各自獨立。Map<K, V>(CH16)就是標準例。慣例:T 型別、E 元素、K 鍵、V 值。
萬用字元
List<?> // 無界:任何型別,只能讀為 Object、不能 add
List<? extends Number> // 上界:讀(producer),不能 add
List<? super Integer> // 下界:寫(consumer),可 add Integer
泛型不協變:List<Integer> 不是 List<Number> 的子型別。口訣 PECS:要讀用 extends、要寫用 super。
底層機制
Box<Integer> bi; Box<String> bs;
bi.getClass() == bs.getClass(); // true(都是 Box.class)
T 被抹成上界(預設 Object)new T[]、T.class、instanceof List<String>接下來