一文搞懂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);
    }
}

 

轉載:https://www.cnblogs.com/minghaiJ/p/10685930.html

 

 


免責聲明!

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



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM