在 JDK 1.5 之前,若想設計一個可容納任意型別的容器(如座標點),只能使用 Object 型別,導致兩大問題:
ClassCastException。(String)obj。使用型別參數 <T> 延遲型別綁定至實例化時:
class Point<T> {
private T x, y;
public Point(T x, T y) { this.x = x; this.y = y; }
public T getX() { return x; }
public void setX(T x) { this.x = x; }
// ... 同理 y
}
// 使用
Point<Double> p1 = new Point<>(12.23, 23.21); // 無需轉型
Point<Integer> p2 = new Point<>(12, 23);
Point<String> p3 = new Point<>("北緯29度", "東經113度");
編譯器會強制檢查:new Point<Double>("str", 1.2) 直接報錯,消除執行期型別風險。
為相容舊代碼,允許不指定型別參數:Point p = new Point(1.2, 3.4);。編譯器會發出「未檢查」警告,實際視為 Object 處理。
型別參數宣告在修飾符與回傳型別之間,適用於單一操作需支援多型別:
class Print {
public <T> void print(T t) { System.out.println(t); }
public <E> void show(E e) { System.out.println(e); }
}
// 呼叫
Print p = new Print();
p.print(12);
p.print("hello");
p.show(new Integer(33));
此處泛型僅提供語法糖,配合自動裝箱/拆箱,實際與 Object 參數差異不大。
兩種實作方式:
interface Inter<T> { void print(T t); }
// 方式一:實作時指定具體型別
class InterDemo1 implements Inter<String> {
public void print(String t) { System.out.println("print: " + t); }
}
// 方式二:保持泛型,實例化時確定
class InterDemo2<T> implements Inter<T> {
public void print(T t) { System.out.println("print: " + t); }
}
// 使用
new InterDemo1().print("hello");
new InterDemo2<Integer>().print(23);
| 語法 | 含義 | 適用場景 |
|---|---|---|
<? extends Number> | 上界通配符,只能讀取 | 消費者(Producer Extends) |
<? super Integer> | 下界通配符,只能寫入 | 生產者(Consumer Super) |
<?> | 無界通配符,等同 <? extends Object> | 僅需 Object 方法時 |
Java 泛型僅存在於編譯期,執行期會被擦除為原始型別(Object 或邊界型別)。因此:
new T()、T.class、instanceof T。extends(生產者),回傳用 super(消費者)——PECS 原則。Class<T> 或使用 TypeToken(Gson 模式)。泛型將型別檢查前置至編譯期,大幅提升程式碼安全性與可讀性。理解類型擦除、通配符邊界、PECS 原則,是精通 Java 集合框架與 API 設計的關鍵。