Generics 是 JDK 5.0 最重要的特性之一,旨在解決集合框架中的類型安全與強制轉型問題。本文通過完整代碼範例,系統講解基本用法、通配符(?)、上下界通配符、泛型方法三大核心語法,並對比 C++ 模板差異。
// JDK 1.4 風險寫法
List list = new LinkedList();
list.add(new Integer(0));
Integer x = (Integer) list.iterator().next(); // 需強轉,運行時才發現類型錯誤
// JDK 5.0 泛型寫法
List<Integer> list = new LinkedList<Integer>();
list.add(new Integer(0));
Integer x = list.iterator().next(); // 編譯期保證類型安全,無需強轉
泛型資訊僅存在編譯期(類型擦除),運行期實際為原始類型。但編譯器插入隱式轉型與檢查,消除了 ClassCastException 風險。
?:未知類型的靈活處理Collection<?>表示「某種具體類型的集合,但類型未知」。
Object,for (Object e : c) 安全。c.add(new Object()) 編譯錯誤(除 null),因無法確認類型相容。但可調用 get() 讀取。public void printAll(Collection<?> c) {
for (Object e : c) System.out.println(e);
}
<? extends Shape>表示「Shape 或其子類型」。
Shape,可安全調用 draw()。shapes.add(new Rectangle()) 錯誤,因集合實際可能是 List<Circle>,加入 Rectangle 違反類型契約。public void drawAll(List<? extends Shape> shapes) {
for (Shape s : shapes) s.draw();
// shapes.add(new Rectangle()); // 編譯錯誤
}
<? super Circle>表示「Circle 或其父類型」。
Circle 或其子類。Object:因實際類型可能是 Object 或 Shape。PECS 原則:Producer Extends, Consumer Super。頻繁讀取用 extends,頻繁寫入用 super。
方法簽名帶類型參數,調用時自動推斷或顯式指定:
public static <T> void copy(List<T> src, List<T> dest) { ... }
// 調用
copy(intList, objList); // T 推斷為 Integer? 實際需兼容性檢查
copy(intList, intList); // OK
泛型方法配合通配符,能寫出極具復用性的工具方法(如 Collections.sort、Collections.copy)。
List<Integer>.class == List<String>.class);C++ 可通過模板特化實現類型相關邏輯。? extends/? super 設計寬容度高的 API(如 addAll(Collection<? extends E>))。instanceof 檢查泛型參數(擦除後無效),改用類型令牌或工廠模式。new List<String>[10] 非法,改用 List<List<String>>。泛型是 Java 類型系統的重大增強,掌握其語法精髓與通配符邏輯,能寫出更安全、自文檔化、可復用的代碼。