1. 程式人生 > 實用技巧 >關於泛型的萬用字元一些補充

關於泛型的萬用字元一些補充

關於泛型萬用字元的一些補充

extends萬用字元

public class Hello_2 {
    public static void main(String[] args) {
        Pair<Integer> p = new Pair<>(123, 456);
        int n = add(p);
        System.out.println(n);
    }

    /*
        接受Integer型別,變成Pair<Integer>,setFirst(Integer first)無法接受Integer型別
        但是可以返回Integer型別,換言之:“只可讀,不可寫”
     */
    static int add(Pair<? extends Number> p) {
        // 正常返回結果
        Number first = p.getFirst();
        Number last = p.getLast();
// 		編譯出錯
//        p.setFirst(new Integer(first.intValue() + 100));
//        p.setLast(new Integer(last.intValue() + 100));

        return p.getFirst().intValue() + p.getLast().intValue();
    }
}

class Pair<T> {
    private T first;
    private T last;

    public Pair(T first, T last) {
        this.first = first;
        this.last = last;
    }

    public T getFirst() {
        return first;
    }
    public T getLast() {
        return last;
    }
    public void setFirst(T first) {
        this.first = first;
    }
    public void setLast(T last) {
        this.last = last;
    }
}

該萬用字元限定泛型型別T的上界(包括自身)

如上述示例程式碼,如果去掉setFirst等的註釋,那麼會出現一個編譯錯誤。

為什麼p的定義是Pair<? extends Number>,那麼setFirst(? extends Number)為什麼不能傳入Integer

原因:擦拭法

如果我們傳入的pPair<Double>,顯然它滿足引數定義Pair<? extends Number>,然而,Pair<Double>setFirst()顯然無法接受Integer型別。

這就是<? extends Number>萬用字元的一個重要限制:方法引數簽名setFirst(? extends Number)

無法傳遞任何Number型別給setFirst(? extends Number)

<? extends Number>型別的形參不能接受Number型別的實參

這裡唯一的例外是可以給方法引數傳入null

p.setFirst(null); // ok, 但是後面會丟擲NullPointerException
p.getFirst().intValue(); // NullPointerException

即一句話總結:使用extends萬用字元表示可以讀,不能寫,,上界<? extends T>不能往裡存,只能往外取。


super萬用字元

與extends相反

下界<? super T>不影響往裡存,但往外取只能放在Object物件裡


PECS原則

最後看一下什麼是PECS(Producer Extends Consumer Super)原則,已經很好理解了:

  • 頻繁往外讀取內容的,適合用上界Extends。
  • 經常往裡插入的,適合用下界Super。