Java 泛型自 JDK 5.0 引入以來,已成為現代 Java 開發中不可或缺的核心特性。它不僅提升了代碼的類型安全性,還大幅減少了強制類型轉換的錯誤風險。本文將系統性地探討 Java 泛型的基本概念、與 C# 泛型的本質差異、類型擦除機制、類型參數限定以及實際開發中的應用模式。
泛型本質上是「類型參數化」,允許在定義類、接口和方法時使用類型參數,並在實際使用時再指定具體類型。這使得同一段代碼能夠處理多種數據類型,實現了算法的復用與類型安全的雙重保障。
這是理解 Java 泛型最關鍵的理論基礎:
ArrayList<Integer> 和 ArrayList<String> 在編譯後都是同一個 ArrayList 類型。泛型信息僅存在於編譯階段,運行時會被擦除為原始類型。這導致基本類型(如 int)必須經過「裝箱/拆箱」轉換為包裝類型(Integer),帶來性能開銷。List<int> 和 List<string> 在運行時是截然不同的類型。泛型參數在運行時保留並具體化,擁有獨立的虛方法表與類型元數據。基本類型無需裝箱/拆箱,性能優於 Java 集合泛型。核心啟示:Java 採用類型擦除主要為了保持與舊版本 JVM 的二進制兼容性,這是一項工程妥協而非設計缺陷。
ClassCastException無泛型時代,集合可存入任意對象,取出時需強制轉型,極易在運行期拋出異常:
ArrayList list = new ArrayList();
list.add("abc");
list.add(123); // 編譯通過,隱患埋下
String s = (String) list.get(1); // 運行時拋出 ClassCastException
引入泛型後,編譯器強制約束元素類型:
ArrayList<String> list = new ArrayList<String>();
list.add("abc");
list.add(123); // 編譯直接報錯
String s = list.get(0); // 無需強轉,類型安全
以 ArrayList.add(E e) 為例,同一方法簽名可服務 String、Integer、自定義對象等任意類型,極大減少重複代碼。
public class Factory<T> {
private T value;
public T getValue() { return value; }
public void setValue(T v) { this.value = v; }
}
// 使用
Factory<String> factory = new Factory<>();
factory.setValue("Hello Generics");
interface Processor<T, R> {
R process(T input);
}
class StringLengthProcessor implements Processor<String, Integer> {
public Integer process(String input) {
return input.length();
}
}
public static <T> void swap(T[] arr, int i, int j) {
T temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
<T extends Comparable>若需在泛型方法中調用 compareTo,必須限定 T 實現 Comparable:
public static <T extends Comparable<T>> T max(T a, T b) {
return a.compareTo(b) >= 0 ? a : b;
}
<T extends A & B & C>& 分隔<T extends Object & Comparable & Serializable>| 場景 | 建議 |
|---|---|
| 集合聲明 | 優先使用 List<String> list = new ArrayList<>();(鑽石語法) |
| 通配符 | 生產者用 extends(PECS 原則),消費者用 super |
| 基本類型 | 無法直接作為類型參數,需用包裝類型(Integer 而非 int) |
| 泛型數組 | 不可直接創建 new T[10],建議用 List 或反射創建 |
| 靜態上下文 | 靜態方法/字段無法使用類的類型參數,需自行聲明泛型方法 |
Java 泛型雖基於類型擦除實現(偽泛型),但通過編譯器的強力檢查,依然在工程實踐中提供了極佳的類型安全與代碼復用能力。深入理解其擦除機制、限定邊界、通配符規則,是編寫健壯、可維護 Java 代碼的關鍵進階技能。
本文旨在梳理 Java 泛型核心知識體系,如有遺漏或不當之處,歡迎留言指正交流。