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

Java 泛型通配符完全指南:? extends T 與 ? super T 的選擇法則

     編輯:Java 相關知識

為什麼需要通配符?

Java 泛型不具協變性:List<Integer> 不是 List<Number> 的子型別。若方法簽名為 void put(Box<Number> box),無法傳入 Box<Integer>,嚴重限制 API 靈活性。有界通配符正是為此而生:

  • ? extends T —— 上界:讀取場景,表示「T 或 T 的子型別」。
  • ? super T —— 下界:寫入場景,表示「T 或 T 的父型別」。

PECS 原則(Producer Extends, Consumer Super)

場景通配符典型方法說明
只讀取(生產者)? extends TT get()取出元素安全視為 T;不可寫入(除 null)
只寫入(消費者)? super Tvoid put(T)放入 T 安全;取出只能視為 Object
既讀又寫無通配符(確切類型)T get(); void put(T)需精確型別,失去多態彈性

實戰範例:Box 容器

interface Box<T> {
    T get();
    void put(T item);
    // 讀取協變:允許傳入 Box<Integer> 給 Box<? extends Number>
    void putFrom(Box<? extends T> src);
    // 寫入逆變:允許將 Box<Number> 當作 Box<? super Integer>
    void copyTo(Box<? super T> dest);
}

常見錯誤與修正

  1. 集合參數用 Collection<T> 而非 Collection<? extends T>
    void process(Collection<Integer> c) → void process(Collection<? extends Number> c),否則無法傳入 List<Integer> 給期望 Number 的 API。
  2. Comparator 等回調應用 ? super T
    void sort(List<T> list, Comparator<? super T> cmp),允許 Comparator<Object> 比較 String。

JDK 實戰教訓

AbstractExecutorService.invokeAll(Collection<Callable<T>>) 初版強制 Callable<T>,導致無法傳入 List<MyTask extends Callable<String>>。Java 6 修正為 Collection<? extends Callable<T>>,完美詮釋 PECS。

總結口訣

「只讀用 extends,只寫用 super,既讀又寫不用通配符」—— 牢記 PECS,API 設計不再踩坑。

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