Generics(泛型)是 JDK 5 最重要的新特性,主要解決集合類型安全問題,類似 C++ 模板但採用類型擦除實現。本文通過完整可編譯範例,系統演示核心用法。
// JDK 1.4 風險寫法
List list = new LinkedList();
list.add(new Integer(0));
Integer x = (Integer) list.iterator().next(); // 需強轉,運行時才報錯
// JDK 5 泛型寫法
List<Integer> list = new LinkedList<Integer>();
list.add(new Integer(0));
Integer x = list.iterator().next(); // 編譯期類型檢查,無需強轉
?</code>表示未知類型,僅能讀取為 Object,不能添加元素(除 null)。適用於只讀操作,如打印集合:
public void print(Collection<?> c) {
for (Object e : c) System.out.println(e);
}
? extends T限定為 T 或其子類。可讀取為 T,但不可寫入(因無法確定具體子類型)。典型場景:drawAll(List<? extends Shape>) 繪製各種圖形。
? super T限定為 T 或其父類。可寫入 T 及其子類,讀取只能作 Object。適用於消費者模式,如 Sink<? super T>。
方法級別聲明類型參數,實現跨類型復用:
public <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) c.add(o);
}
// 調用時編譯器自動推導 T
fromArrayToCollection(new String[10], new ArrayList<String>());
fromArrayToCollection(new Integer[10], new ArrayList<Number>()); // T 推導為 Number
List<List<? extends Shape>>new ArrayList<String>().getClass() == new ArrayList<Integer>().getClass() // truenew List<String>[10] 非法),需用無界通配符數組替代。// 類型安全的 Sink 接口,避免為每種類型定義重載方法
interface Sink<E> { void flush(E t); }
// 協變返回類型與通配符結合
public <T> T writeAll(Collection<T> coll, Sink<T> snk) { ... }
public <T> T writeAll1(Collection<? extends T> coll, Sink<T> snk) { ... }
public <T> T writeAll2(Collection<T> coll, Sink<? super T> snk) { ... }
Generics 將類型檢查前移至編譯期,消除強轉,提升代碼可讀性與安全性。掌握通配符邊界(PECS 原則:Producer Extends, Consumer Super)是靈活運用的關鍵。