Java泛型通配符:上界與下界,簡單理解

爲什麼需要泛型通配符?

在Java泛型中,我們常常會遇到需要處理一類集合的情況:比如,一個方法可能需要同時處理List<Integer>List<Double>List<Number>等不同類型的集合,但又不想爲每個類型單獨寫一個方法。這時候,泛型通配符就能派上用場了。

通配符用?表示,分爲兩種:上界通配符? extends T)和下界通配符? super T),它們能幫助我們統一處理不同子類型的泛型集合,同時保證類型安全。

一、上界通配符(? extends T

什麼是上界通配符?

上界通配符表示:集合中的元素類型是T子類或T本身
語法:List<? extends T>List<? extends Number>(假設TNumber)。

舉個例子

假設我們有一個類層次結構:Object是根類,Number繼承ObjectIntegerDouble繼承Number
如果我們想寫一個方法,能打印所有Number類型(及其子類)的集合元素,可以這樣寫:

// 打印List中所有元素
public static void printNumbers(List<? extends Number> list) {
    for (Number num : list) { // 元素一定是Number類型,安全
        System.out.println(num);
    }
}

// 調用方法
List<Integer> intList = Arrays.asList(1, 2, 3);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
List<Number> numberList = Arrays.asList(10, 20.5, 30);

printNumbers(intList);   // 正確(Integer是Number子類)
printNumbers(doubleList); // 正確(Double是Number子類)
printNumbers(numberList); // 正確(Number是上界)

上界通配符的特點

  1. 只能獲取元素,不能添加元素
    因爲編譯器不知道集合具體是哪個子類(如List<Integer>List<Double>),如果嘗試添加元素,類型可能不匹配。
    ❌ 錯誤示例:list.add(new Integer(10));
    ✅ 正確:只能獲取元素,返回類型是T(如Number)。

  2. 返回元素類型安全
    元素一定是T或其子類,因此可以用T類型接收(如Number)。

二、下界通配符(? super T

什麼是下界通配符?

下界通配符表示:集合中的元素類型是T父類或T本身
語法:List<? super T>List<? super Number>(假設TNumber)。

舉個例子

假設我們想寫一個方法,能往集合中添加Number類型及其子類(如IntegerDouble)的元素,同時處理不同父類的集合(如List<Object>List<Number>):

// 往集合中添加Number類型及其子類
public static void addNumbers(List<? super Number> list) {
    list.add(new Integer(10));  // 正確(Integer是Number子類)
    list.add(new Double(20.5)); // 正確(Double是Number子類)
    list.add(new Number(30));   // 正確(Number是上界)
}

// 調用方法
List<Object> objList = new ArrayList<>();
List<Number> numList = new ArrayList<>();
List<Integer> intList = new ArrayList<>();

addNumbers(objList);   // 正確(Object是Number的父類)
addNumbers(numList);   // 正確(Number是Number的父類)
addNumbers(intList);   // 正確(Integer是Number的子類,可作爲父類集合處理)

下界通配符的特點

  1. 只能添加元素,不能獲取具體類型元素
    因爲集合可能是ObjectNumber等父類集合,元素類型不確定,只能返回Object
    ❌ 錯誤示例:Number num = list.get(0);
    ✅ 正確:只能獲取Object類型元素。

  2. 添加元素類型安全
    可以添加T或其子類,編譯器能保證類型匹配。

三、關鍵區別與場景總結

通配符類型 定義 核心特點 適用場景
? extends T 元素是T的子類或T本身 只能獲取元素(返回T),不能添加元素(除null) 需要讀取不同子類集合的元素
? super T 元素是T的父類或T本身 只能添加元素(T或其子類),不能獲取具體類型元素(只能返回Object) 需要往不同父類集合添加元素

四、避坑指南

  1. 上界通配符不能寫“T”,下界通配符不能寫“T”
    通配符是“不確定類型”的佔位符,而T是類型參數(需明確指定類型)。例如:
   // 錯誤寫法(上界通配符不能用T作爲返回類型)
   public static <T extends Number> T getFirst(List<T> list) { ... }
   // 正確寫法(用類型參數T)
  1. 避免過度使用通配符
    如果方法只需要List<Integer>,直接使用List<Integer>更明確。通配符用於“未知具體類型”的場景。

五、一句話總結

  • 上界通配符(? extends T:處理“所有T的子類”,只讀不寫
  • 下界通配符(? super T:處理“所有T的父類”,只寫不讀具體類型

掌握這兩個規則,就能靈活應對Java泛型中不同子類/父類集合的統一處理問題了!

小夜