? 和 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
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯系作者獲得授權並注明出處。
