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

Java 泛型通配符解決方法重載擦除問題深度解析

     編輯:Java 相關知識

問題背景:泛型擦除導致重載失效

Java 泛型採用類型擦除機制,編譯後泛型信息被擦除,導致以下代碼無法編譯:

public class GenericOverload {
    // 編譯錯誤:擦除後簽名相同,均為 print(List)
    public void print(List<Integer> list) { }
    public void print(List<String> list) { }
}

通配符解決方案

使用 <? extends T> 或 <? super T> 讓編譯器識別為不同簽名:

public class GenericWildcard {
    // 編譯通過:擦除後為 print(List<?>) 但編譯器保留泛型簽名差異
    public void print(List<? extends Number> list) { 
        System.out.println("Number 子類列表");
    }
    
    public void print(List<? super Integer> list) { 
        System.out.println("Integer 父類列表");
    }
    
    public void print(List<?> list) { 
        System.out.println("任意類型列表");
    }
}

PECS 原則:何時用 extends / super

場景通配符含義典型用例
只讀取元素<? extends T>上界通配符,元素是 T 或其子類List<? extends Number> → 可讀 Number 及子類
只寫入元素<? super T>下界通配符,元素是 T 或其父類List<? super Integer> → 可寫 Integer 及子類
既讀又寫不使用通配符確切類型List<Integer>

實戰範例:複製集合元素

public static <T> void copy(List<? super T> dest, List<? extends T> src) {
    for (T item : src) {
        dest.add(item); // 安全:src 產出 T,dest 消費 T
    }
}

// 使用
List<Integer> ints = Arrays.asList(1, 2, 3);
List<Number> nums = new ArrayList<>();
copy(nums, ints); // List<Number> 是 List<? super Integer>,List<Integer> 是 List<? extends Number>

通配符捕獲與類型推導

// 編譯器會捕獲具體類型
List<?> list = Arrays.asList("a", "b");
process(list); // 推導為 List<String>

private static <E> void process(List<E> list) {
    E first = list.get(0); // 類型安全
}

其他泛型「詬病」與應對

  • 無法創建泛型數組:new List<String>[10] 非法 → 使用 List<List<String>> 或 @SuppressWarnings("unchecked")
  • 無法 instanceof 泛型:list instanceof List<String> 非法 → 檢查原始類型 list instanceof List
  • 靜態上下文無法使用類型參數:靜態方法/字段不能引用類的泛型參數 → 將方法改為泛型方法

總結

通配符是 Java 泛型擦除機制下的妥協產物,通過 ? extends T(生產者)和 ? super T(消費者)實現了協變與逆變,解決了方法重載衝突並增強了 API 靈活性。掌握 PECS 原則是編寫優雅泛型代碼的關鍵。

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