關於泛型的萬用字元一些補充
阿新 • • 發佈:2020-08-23
關於泛型萬用字元的一些補充
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
?
原因:擦拭法
如果我們傳入的p
是Pair<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。