一文搞懂List 、List、List 的區別以及 的區別

前段時間看《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);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。