首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 泛型深度解析:從類型擦除到通配符上下界、自定義泛型類/接口/方法完整指南

     編輯:Java 相關知識

為什麼需要泛型?

預泛型時代:List list = new ArrayList(); list.add("A"); list.add(100); 取出時需強轉,運行期才發現 ClassCastException。**泛型將類型檢查前置到編譯期**,實現「編譯不報錯,運行不拋異常」。

核心概念:參數化類型

  • List<String> 中 String 為 **類型實參**。
  • interface List<E> 中 E 為 **類型形參**。
  • 編譯期經過 **類型擦除**,運行期只剩原始類型 List,泛型信息不進入字節碼(簽名除外)。

自定義泛型:類、接口、方法

1. 泛型類

public class Box<T> {
    private T value;
    public Box(T value) { this.value = value; }
    public T get() { return value; }
    public void set(T value) { this.value = value; }
}

// 使用
Box box = new Box<>("Hello");
String s = box.get(); // 無需強轉

2. 泛型接口

public interface Repository<T, ID> {
    T findById(ID id);
    List<T> findAll();
    T save(T entity);
}

3. 泛型方法(類不泛型,方法泛型)

public class Util {
    // 靜態泛型方法
    public static <T> List<T> asList(T... arr) {
        return Arrays.asList(arr);
    }
    // 實例泛型方法
    public <T> T first(Collection<T> c) {
        return c.iterator().next();
    }
}

// 調用:類型推導自動匹配
List nums = Util.asList(1, 2, 3);
String first = Util().first(List.of("a", "b"));

類型擦除的證據與後果

Box b1 = new Box<>("A");
Box b2 = new Box<>(1);
System.out.println(b1.getClass() == b2.getClass()); // true,運行期同一 Class 對象
// new T()、T[]、instanceof T、T.class 均非法

通配符:? extends T(上界) vs ? super T(下界)

通配符含義能讀取能寫入PECS 原則
<? extends Number>Number 或其子類✅ (作為 Number)❌ (除 null)Producer Extends
<? super Integer>Integer 或其父類❌ (只能作 Object)✅ (接受 Integer 及子類)Consumer Super
<?>任意類型✅ (作 Object)❌雙向只讀

實戰:複製集合元素

public static void copy(List<? super T> dest, List<? extends T> src) {
    for (T t : src) dest.add(t); // src 只讀,dest 只寫,完美匹配 PECS
}

泛型與數組:不兼容

  • 數組是**協變** 的:Integer[] → Number[] 合法,運行期檢查存入類型。
  • 泛型是**不變** 的:List → List **非法**。
  • **不能創建泛型數組**:new List[10] 編譯錯誤。替代方案:List> 或 new ArrayList<>()[10](非泛型數組)。

進階:有界類型參數、多重界限、遞歸類型界限

<T extends Number & Comparable<T>> // 多重界限
<T extends Comparable<? super T>> // 遞歸界限:自身可比較(Enum、String、包裝類均符合)

避坑清單

  1. **基本類型不能作類型參數**:用包裝類 List ❌ → List ✅。
  2. **靜態上下文不能使用類的類型參數**:static T field; ❌,泛型方法自帶類型參數 ✅。
  3. **instanceof 泛型非法**:obj instanceof List ❌,用 instanceof List + 遍歷檢查。
  4. **類型擦除導致重載衝突**:void m(List) 和 void m(List) 擦除後簽名相同,編譯錯誤。

總結

泛型通過 **編譯期類型參數化 + 運行期類型擦除** 實現類型安全與向後兼容。掌握 **PECS 原則、擦除後果、自定義泛型類/接口/方法、有界參數、避坑清單**,即可在 API 設計、集合框架擴展、框架開發中靈活運用泛型威力。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved