java泛型通配符 ? extends T 和 ? super T 的區別和用法

關於Java泛型,這裏我不想總結它是什麼,這個百度一下一大堆解釋,各種java的書籍中也有明確的定義,只要稍微看一下就能很快清楚.從泛型的英文名字Generic type也能看出,Generic普通、一般、通用的,是一個概括性的詞,那麼泛型從名字上也就好理解了,它是一種通用類型,是java中各種類型的概括.

?是java泛型中的通配符,它代表java中的某一個類,那麼<? extends T>就代表類型T的某個子類,<? super T>就代表類型T的某個父類.

這裏我們先定義一組有繼承關係的類:

//子類-->父類
 
小紅蘋果--紅蘋果--蘋果--水果--好吃的--吃的

這些類都是左側的類爲與它相連接的右側的類的子類.

那麼<? extends 蘋果> 代表的是左側小紅蘋果,紅蘋果和蘋果的類中的某個類,而<? super 蘋果>代表的就是蘋果和水果,好吃的,吃的,的類中的某個類.

這裏要注意的是<? extends T>或是<? super T>代表的是範圍內的某個特定的類,而不是範圍內的所有類.

//所以只要在範圍內,我們可以如下這樣的隨意賦值
List<? extends 蘋果>  list1 = new ArrayList<蘋果>();
List<? extends 蘋果>  list2= new ArrayList<紅蘋果>();
List<? extends 蘋果>  list3 = new ArrayList<小紅蘋果>();

但是對於List<? extends 蘋果> list來說,代表的是一個範圍內的某個類,但是卻不確定是哪個類,所以如果我們向這個list中添加元素的時候:

List<? extends 蘋果>  list = new ArrayList<蘋果>();
list.add(蘋果);    //編譯錯誤
list.add(紅蘋果);    //編譯錯誤
list.add(小紅蘋果);     //編譯錯誤

因爲編譯器並不知道list到底是哪個類(只有在運行的時候才能確定指代的哪個類),如果list是紅蘋果,那麼list.add(蘋果)就將一個父類賦值給子類了,是錯誤的.顯然如果向這個list中添加類,都不能保證是正確的.可能會說小紅蘋果沒有子類,添加小紅蘋果不會錯,但是這只是我定義的一個繼承圖中是這樣,我們完全可以繼續定義個小小紅蘋果來繼承小紅蘋果,這個繼承是沒有下限的.這個反推出一個結論<? extends T>是一個有上限T的類型.那麼我們馬上就發現<? super T>實際上是有下限T的類型.

因爲對於<? extends T>有上限T,故我們如果list.get(0)一定返回的是T或是T的子類,這個是確定的,得出:

List<? extends 蘋果>  list1 = new ArrayList<蘋果>();
蘋果 a = list1.get(0);  //這個是一定成立的,編譯也不會有問題
List<? extends 蘋果>  list2 = new ArrayList<紅蘋果>();
蘋果 a = list2.get(0);  
List<? extends 蘋果>  list3 = new ArrayList<小紅蘋果>();
蘋果 a = list3.get(0); 

然後我們來看<? super T>,因爲它有下限,故我們可以馬上得出,如果向其中添加T類型的對象是沒問題的.因爲<? super T>是T的某個父類,將子類T賦值給父類沒任何問題:

List<? super 蘋果>  list = new ArrayList<蘋果>();
list.add(蘋果);    //無任何問題
List<? super 蘋果>  list = new ArrayList<水果>();
list.add(蘋果);    //無任何問題
發佈了35 篇原創文章 · 獲贊 11 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章