?
和 T
是什么?
?
是通配符,T
是類型變量。根據字面意思,<? extends T>
表示 任何繼承自類型 T
的類型,<? super T>
表示 任何是類型 T
的超類的類型。
上界和下界

泛型的關系-extends.png
下面代碼就是 上界通配符(Upper Bounds Wildcards)
Plate<? extends Fruit>
它的表意是,一個能放 Fruit
及其子類的盤子。

泛型的關系-super.jpg
下面代碼就是 下界通配符(Lower Bounds Wildcards)
Plate<? super Fruit>
它的表意是,一個能放 Fruit
及其父類的盤子。
PECS 原則
1. <? extends T> 不能往里存,只能往外取
class Plate<T> { private T item; public Plate(T t) { item = t; } public void set(T t) { item = t; } public T get() { return item; } }
往里存的意思就是,不能對泛型 T
類型所代表的成員變量 item
進行賦值(賦值成一種特定類型)。往外取的意思就是對泛型 T
類型所代表的成員變量 'item' 進行進行類型轉換(轉換成一種特定類型)。
Plate<? extends Fruit> p = new Plate<Apple>(new Apple()); // 不能被存入任何元素 p.set(new Fruit()); // exception p.set(new Apple()); // exception // 取出來的東西只能放在 Fruit 或它的基類里 Fruit fruit = p.get(); Object object = p.get(); Apple apple = p.get();
- 注意以上代碼,只有在構造函數中可以對
T
類型的item
進行賦值,通過set
方法進行賦值是不行的。原因是編譯器通過<? extends Fruit>
只知道Plate
接受的是Fruit
及其子類,但是具體是哪個不能確定。但是從寫法上,我們在構造時已經顯式地指明了Plate
的類型是Apple
,為什么編譯器還不知道呢?這是因為 JVM 在設計初期就沒有考慮過泛型,因此對於 JVM 編譯成的字節碼來說,也沒有泛型的概念,JVM 會使用一個占位符 CAP#1 來表示Plate
接受一個Fruit
或子類。所以無論想往Plate
插入任何類型都不可以(因為你不能賦值一個 CAP#1 類型) - 但是,將 <? extends Fruit> 替換為一個具體的類型,
set
方法就是生效的。這是因為編譯器已經知道Plate
只會接受一個確定類型的水果Apple
。
Plate<Apple> applePlate = new Plate<>(new Apple()); applePlate.set(new Apple()); Apple apple = applePlate.get(); applePlate.set(new GreenApple());
- 但是下面的寫法是不被接受的。因為泛型
T
是一個類型變量,它不能被用於表達式中。
Plate<T extends Fruit> p = new Plate<>(new Apple());
- 如果寫
Plate<?>
,則表示Plate
中放的是任意類型,因此什么也存不進去,可以往外取Object
Plate<?> anyPlate = new Plate<>(new Apple()); Object o = anyPlate.get();
其實存不進去的根本原因是因為,Java 類沒有一個共同的子類,但是卻有一個共同的父類
Object
。所以永遠可以向上轉型取數據,卻不能向下轉型存數據。
2. 下界 <? super Fruit> 不影響往里存,但是往外取只能放在 Object
使用下界 <? super Fruit>
的意思是,Plate
中存放的是任意 Fruit
的基類,但是不確定是哪一個。因此往里放 Fruit
以及其子類一定是可以的(因為這些類一定是 <? super Fruit>
的子類)。但是往外取時就只能是 Object
,因為編譯器不知道你存的是 Fruit
還是 Meat
。Fruit
和 Meat
就只有一個共同父類,那就是 Object
。因此往外取 Object
一定是對的。
3. PECS(Producer Extends Consumer Super)
3.1 Producer Extends 你寫的類是主要作為生產者向外提供數據,那么就用 extends
3.2 Consumer Super 你寫的類是主要作為消費者,需要吃進數據,那么就用 super
作者:你可記得叫安可
鏈接:https://www.jianshu.com/p/0808c0029b2d
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。