| 形式 | 位置 | 含義 |
<T extends E> | 類定義後、方法返回值前 | 聲明一個類型參數 T,T 是 E 的子類型 |
<? extends E> | 泛型變量聲明處(實例化時) | 實例化類型參數為「E 或 E 的某個未知子類型」 |
三、通配符的「只讀」本質:為什麼不能寫入?
DynamicArray<Integer> ints = new DynamicArray<>();
DynamicArray<? extends Number> nums = ints; // 合法:上界通配符
nums.add(100); // 編譯錯誤!
nums.add(new Double(1.0)); // 編譯錯誤!
nums.add(new Object()); // 編譯錯誤!
原因:? extends Number 表示「某個具體的 Number 子類型」,但編譯器不知道具體是哪個。允許寫入會破壞類型安全(如向 Integer 列表寫入 Double)。
四、無限定通配符 <?>:最寬鬆的只讀視圖
// 原版:只能寫入完全相同類型
public void copyTo(DynamicArray<E> dest) { ... }
// 改進:使用下界通配符,允許寫入 E 的父類型容器
public void copyTo(DynamicArray<? super E> dest) {
for (int i = 0; i < size; i++) dest.add(get(i));
}
// 使用示例
DynamicArray<Integer> ints = ...;
DynamicArray<Number> nums = ...;
ints.copyTo(nums); // 合法!Integer 寫入 Number 容器
? super E 表示「E 的某個父類型」。既然容器能裝父類型,裝子類型當然安全。
場景 2:靈活比較——Comparable/Comparator 的經典應用
| 場景 | 推薦形式 | 理由 |
| 只需讀取,類型無依賴 | <?> / <? extends E> | 簡潔、可讀性強、接受更廣類型 |
| 需要寫入容器 | <? super E> | 唯一能實現安全寫入的形式 |
| 類型參數之間有依賴關係 | <T>, <S extends T> | 通配符無法表達多參數依賴 |
| 返回值依賴類型參數 | <T> | 通配符無法在返回類型中引用 |
| 內部實現需要類型安全操作 | 公共 API 用通配符,內部調用類型參數方法 | 兼顧簡潔與類型安全 |
七、JDK 集合框架中的經典用法
// Collections 工具類
public static <T extends Comparable<? super T>> void sort(List<T> list)
public static <T> void sort(List<T> list, Comparator<? super T> c)
public static <T> void copy(List<? super T> dest, List<? extends T> src)
public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
完美體現:讀取用 extends,寫入用 super,比較用 super,拷貝 src 用 extends、dest 用 super。
八、小結
<?>、<? extends E>:靈活讀取,可用類型參數替代,但通配符更簡潔。
<? super E>:靈活寫入與比較,無法用類型參數替代,是泛型類型系統表達力的關鍵補充。
- 實戰原則:公共 API 優先用通配符簡化簽名,內部實現用類型參數保證類型安全。
掌握通配符,是寫出優雅、健壯、可復用泛型代碼的關鍵一步。
- 上一篇文章: Activiti 源碼深度解析(一):命令模式與責任鏈模式的完美融合
- 下一篇文章: WebSocket 與即時訊息推送:從原理到 Java 實戰完整指南
Copyright ©
程式碼之家 All Rights Reserved