前段時間看《Java編程思想》泛型時對 <? extends T>與<? super T>很懵逼,接着看到泛型與集合的更蒙蔽,隨后又翻開《碼出高效》時,對這些知識點才恍然大悟,發篇博客記錄下
List、List<Object>、List<?> 的三者的區別以及 <? extends T>與<? super T> 的區別
List、List<Object>、List<?>
- List :完全沒有類型限制和賦值限定。
- List<Object> :看似用法與List一樣,但是在接受其他泛型賦值時會出現編譯錯誤。
- List<?>:是一個泛型,在沒有賦值前,表示可以接受任何類型的集合賦值,但賦值之后不能往里面隨便添加元素,但可以remove和clear,並非immutable(不可變)集合。List<?>一般作為參數來接收外部集合,或者返回一個具體元素類型的集合,也稱為通配符集合。
代碼驗證:(感覺用博客的頁面插入代碼效果不好,在此處貼了圖片,代碼在文章末尾補上)

<? extends T>與<? super T>
List 最大的問題是只能放置一種類型,如果隨意轉變類型的話,就是破窗理論,泛型就失去了意義。為了放置多種受泛型約束的類型,出現了 <? extends T>與<? super T> 兩種語法。簡單來說, <? extends T> 是Get First,適用於,消費集合元素的場景;<? super T>是Put First,適用於,生產集合元素為主的場景。
- <? extends T> :可以賦值給任意T及T的子類集合,上界為T,取出來的類型帶有泛型限制,向上強制轉型為T。null 可以表示任何類型,所以null除外,任何元素都不得添加進<? extends T>集合內。
- <? super T> : 可以復制T及任何T的父類集合,下界為T。再生活中,投票選舉類似於<? super T>的操作。選舉投票時,你只能往里投票,取數據時,根本不知道時是誰的票,相當於泛型丟失。
<? extends T>的場景是put功能受限,而<? super T>的場景是get功能受限。
代碼示例如下(以加菲貓、貓、動物為例,說明extends和super的詳細語法差異0):


在代碼第二段中的23行編譯時報錯:
Type mismatch: cannot convert from List to List<? extends Cat> ,
因為List賦值給List時會編譯出錯,因為能賦值給<? extends Cat>的類型,只有Cat和它的子類。因為<? extends Cat>泛型信息表示的是,此籠子(容器)內的全部都是貓,而List籠子(容器)內可能住着毒蛇,鱷魚、豹貓(貓的天敵)、大型猛禽等動物,不能把它們放同一個籠子(容器)里。 26,27行中,把List賦值給 <? extends T>與<? super T> 都是可以的。
在第三段代碼的36、36、37行均編譯出錯:
The method add(capture#1-of ? extends Cat) in the type List<capture#1-of ? extends Cat> is not applicable for the arguments (Animal)
無法進行add操作,這是因為除null外,任何元素都不能添加進<? extends T>集合中。但<?super Cat>可以往里面添加元素,但只能添加Cat自身即其子類對象,如上面代碼中的41、42行。因為貓的籠子中只能關貓,不能關其他動物,如代碼中的40行。
在上面代碼中的第四段中,所有的 List<? super T>集合 都能執行get方法返回元素,但是泛型丟失,只能返回object對象,如上面代碼中的46、47、48行。List<? extends T>集合 可以返回帶類型的元素,但只能返回Cat自身及其父類對象,因為子類對象被擦除了,如代碼中的50到54行。
附:
第一張圖片中的代碼
import java.util.ArrayList;
import java.util.List;
public class TestArrayList {
public static void main(String[] args) {
//第一段:泛型出現之前集合定義方式
List a1 =new ArrayList();
a1.add(new Object());
a1.add(new Integer(10));
a1.add(new String("string"));
//第二段:把a1引用賦值給a2,(a2與a1的區別是增加了泛型限制)
List<Object> a2 =a1;
a2.add(new Object());
a2.add(new Integer(20));
a2.add(new String("string2"));
a2.add(25);
//List<Object> 接受其他泛型賦值時,會報異常(因為在下面例子中List<Integer>不能轉為List<Object>)
List<Integer> aint = new ArrayList<Integer>();
List<Object> a22 =aint;//Type mismatch: cannot convert from List<Integer> to List<Object>
//第三段:把a1引用賦值給a3,(a3與a1的區別是增加了泛型<Integer>)
List<Integer> a3 = a1; //此時如果遍歷a3則會報類型轉換異常ClassCastException
a3.add(new Integer(20));
//下面兩行編譯出錯,不允許增加非Integer類型進入集合
a3.add(new Object());//The method add(Integer) in the type List<Integer> is not applicable for the arguments (Object)
a3.add(new String("string2"));
//第四段:把a1引用賦值給a4,a4與a1的區別是增加了通配符
List<?> a4 = a1;
//允許刪除和清除元素
a4.remove(0);
a4.clear();
//編譯錯誤,不允許添加任何元素
a4.add(new Object());//The method add(capture#3-of ?) in the type List<capture#3-of ?> is not applicable for the arguments (Object)
a4.add(new Integer(20));
a4.add(new String("string2"));
}
}
第二張圖片中的代碼
import java.util.ArrayList;
import java.util.List;
class Animal{}
class Cat extends Animal{}
class Garfield extends Cat{}
//用動物,貓,加菲貓的繼承關系說明extends與super在集合中的意義
public class AnimalCatGarfield {
public static void main(String[] args) {
//第一段:聲明第三個依次繼承的集合:Object>動物>貓>加菲貓 三個泛型集合可以理解為三個不同的籠子
List<Animal> animal = new ArrayList<Animal>(); //動物
List<Cat> cat = new ArrayList<Cat>(); //貓
List<Garfield> garfield = new ArrayList<Garfield>(); //加菲貓
animal.add(new Animal());
cat.add(new Cat());
garfield.add(new Garfield());
//第二段:測試賦值操作 以Cat為核心,因為它既有子類又有父類
//下行編譯出錯。只能賦值Cat或Cat子類集合
List<? extends Cat> extendsCatFromAnimal = animal;
List<? super Cat> superCatFromAnimal = animal;
List<? extends Cat> extendsCatFromCat = cat;
List<? super Cat> superCatFromCat = cat;
List<? extends Cat> extendsCatFromGarfield = garfield;
//下行編譯出錯。只能賦值Cat或着Cat父類集合
List<? super Cat> superCatFromGarfield = garfield;
//第三段:測試add方法
//下面三行中所有的<? extends T>都無法進行add操作,編譯出錯
extendsCatFromCat.add(new Animal());
extendsCatFromCat.add(new Cat());
extendsCatFromCat.add(new Garfield());
//下行編譯出錯。只能添加Cat或者Cat的子類集合。
superCatFromCat.add(new Animal());
superCatFromCat.add(new Cat());
superCatFromCat.add(new Garfield());
//第四段:測試get方法
//所有的super操作能夠返回元素,但是泛型丟失,只能返回object對象
Object object1 = superCatFromCat.get(0);
Animal object = superCatFromCat.get(0);//Type mismatch: cannot convert from capture#8-of ? super Cat to Animal
Cat object3 = superCatFromCat.get(0);//
//以下extends操作能夠返回元素
Animal catExtends3 = extendsCatFromCat.get(0);
Object catExtends2 = extendsCatFromCat.get(0);
Cat catExtends1 = extendsCatFromCat.get(0);
//下行編譯錯誤。雖然Cat集合從Garfield賦值而來,但類型擦除后,是不知道的
Garfield cat2 = extendsCatFromGarfield.get(0);
}
}
轉載:https://www.cnblogs.com/minghaiJ/p/10685930.html