JDK 5.0 引入泛型,本質是「參數化型別」:建立類別/介面/方法時將型別抽象為參數,使用時再具體化。類比方法參數:method(String a, String b) 的 a,b 是值參數;class Box<K, V> 的 K, V 是型別參數。
class TestGen<K, V> {
private Hashtable<K, V> h = new Hashtable<K, V>();
public void put(K k, V v) { h.put(k, v); }
public V get(K k) { return h.get(k); }
public static void main(String[] args) {
TestGen<String, String> t = new TestGen<String, String>();
t.put("key", "value");
System.out.println(t.get("key")); // 輸出: value
}
}
實例化時必須指定具體型別(兩處皆需寫入),編譯器負責型別檢查與自動轉型,消除手動強制轉換與 ClassCastException 風險。
<?>List<?> 表示「某種未知型別的 List」。只能讀取為 Object,無法寫入(除 null)。適用於僅讀取元素的通用方法(如列印)。
<? extends T>限定為 T 或其子型別。可讀取為 T,但不可寫入(型別不確定)。List<String> 不是 List<Object> 的子型別——泛型不具協變性。
<? super T>限定為 T 或其父型別。可寫入 T,讀取只能作為 Object。適用於消費者模式(如 Collections.copy(dest, src) 的 dest 為 List<? super T>)。
class TestGen2<K extends String, V extends Number> { ... }
// K 必須是 String 或子類(String 為 final 實際僅能是 String)
// V 可為 Integer, Double, Float 等 Number 子類
多重邊界:<T extends Comparable<? super T> & Serializable>——& 串接多個介面限定。
public void autoBoxingUnboxing(int i) {
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(i); // 自動裝箱 int -> Integer
int a = list.get(0); // 自動拆箱 Integer -> int
}
JDK 5 讓基本型別與包裝類無縫轉換,泛型集合不再需要手動 new Integer(i)。
class TestGen {
public static <T> List<T> make(T first) {
return new ArrayList<T>(Arrays.asList(first));
}
}
方法層級型別參數 <T> 置於修飾符後、回傳型別前,調用時編譯器自動推導型別。
List<String> 變 List)new List<String>[10] 編譯錯誤instanceof 不能檢查具體泛型型別(list instanceof List<String> 非法)