在Java泛型中,extends
通配符用于限定泛型類型的上界,即指定泛型可以是某個類型或其子類型。它有兩種常見用法:類型參數限定和通配符限定,下面詳細介紹:
1. 類型參數限定(在類/方法定義中)
在定義泛型類或方法時,使用extends
關鍵字限制泛型類型必須是某個類(或接口)的子類。
語法:<T extends 上限類型>
- 示例1:限定泛型為
Number
的子類// 泛型類:T必須是Number或其子類(如Integer、Double) class GenericClass<T extends Number> {private T value;public GenericClass(T value) {this.value = value;}public double getDoubleValue() {return value.doubleValue(); // 可調用Number的方法} }// 使用: GenericClass<Integer> intClass = new GenericClass<>(10); // 合法 GenericClass<String> strClass = new GenericClass<>("abc"); // 編譯錯誤(String不是Number子類)
- 示例2:限定多個接口(用
&
分隔)// T必須同時實現Comparable和Serializable接口 class MultiInterface<T extends Comparable<T> & Serializable> {// ... }
2. 通配符限定(在方法參數或變量聲明中)
使用? extends 上限類型
表示未知類型,但必須是指定類型的子類,常用于讀取數據(因為寫入時類型不確定)。
語法:? extends 上限類型
- 示例1:方法參數中使用通配符
// 只能處理Number或其子類的容器,且只能讀取數據 public static void printNumbers(Collection<? extends Number> nums) {for (Number num : nums) {System.out.println(num);}// nums.add(10); // 編譯錯誤:無法向通配符類型添加元素 }// 使用: List<Integer> intList = Arrays.asList(1, 2, 3); printNumbers(intList); // 合法 List<String> strList = Arrays.asList("a", "b"); printNumbers(strList); // 編譯錯誤(String不是Number子類)
- 示例2:通配符與泛型類結合
class Box<T> {private T value;// ... getter/setter }// 定義一個方法,接收"上限為Number"的Box,只能讀取 public static void processBox(Box<? extends Number> box) {Number num = box.getValue(); // 合法// box.setValue(10); // 編譯錯誤:無法確定具體類型 }
3. extends通配符的核心規則
- 只讀原則:
? extends T
類型的集合只能讀取元素(返回類型為T
或其父類),不能寫入元素(因為無法確定具體類型)。
例如:List<? extends Number>
可以讀取Number
,但無法添加任何元素(包括Number
本身)。 - 類型傳遞性:如果
A
是B
的子類,List<A>
是List<? extends B>
的子類型。
4. 與super通配符的對比
extends
通配符(? extends T
):限定類型上限(必須是T或其子類),用于讀取。super
通配符(? super T
):限定類型下限(必須是T或其父類),用于寫入。
示例:// 寫入場景用super: public static void addNumber(List<? super Integer> list, Integer num) {list.add(num); // 合法,因為list元素類型至少是Integer的父類 }
總結
extends
通配符是Java泛型中實現類型安全和靈活兼容的重要工具:
- 定義泛型時,用
<T extends 上限>
限制類型范圍,確保類型操作的合法性。 - 使用泛型時,用
? extends 上限
允許接收子類類型,同時保證讀取操作的安全(但犧牲寫入能力)。
合理使用通配符可以避免類型轉換異常,提升代碼的復用性和可維護性。