泛型與集合

泛型:
類型參數化,解決不確定對象類型的問題。好處是代碼複用性高。

作用範圍:
類,方法,接口。 編譯器通過識別尖括號內的字母來解析泛型。
約定俗成的泛型名: E (Element 集合中元素) , T (the Type of Object)某個類。

應用舉例:
在沒有使用泛型前:

 //未使用 泛型,會出現強制類型轉換報錯風險
    public static Object heap (Object food)
    {
        System.out.println(food + "is done");
        return food;
    }

    public static void main(String[] args) {

        // 加熱肉
        Meat meat  = new Meat();
        Meat me = (Meat)Stove.heap(meat);
        // 加熱湯
        Soup soup  = new Soup();
        Soup soup = (Soup)Stove.heap(soup);

    }

這裏用 Object 來避免爲每種食物都寫一種加熱的方法,但根據墨菲定律,會發生強制類型轉換的危險。

使用泛型:

  public static T heap (T food)
    {
        System.out.println(food + "is done");
        return food;
    }
    public static void main(String[] args) {
        // 加熱肉
        Meat meat  = new Meat();
        Meat me = Stove.heap(meat);
        // 加熱湯
        Soup soup  = new Soup();
        Soup soup = Stove.heap(soup);

    }

好處:不會出現類型轉換的錯誤,代碼複用性高。

泛型與集合的聯合使用:
List, List , List<?> 這三個對象有啥區別?直接看代碼:

public static void main(String[] args)
	{
  //  1 無泛型約束
		List a1 = new ArrayList<>();
		a1.add(new Integer(1));
		a1.add(new Object());
		a1.add("hello");

		//將 a1 的引用賦值給 a2 , 但是在接受其他泛型賦值時會出現編譯錯誤
		List<Object> a2 = a1;
		a2.add(new Integer(1));
		a2.add(new Object());
		a2.add("hello");

		//將 a1 的引用賦值給 a3
		List<Integer> a3 = a1;
		a3.add(new Integer(1));
		a3.add(new Object());
		a3.add("hello");

		//將 a1 的引用賦值給 a4
		List<?>a4 = a1;
		a4.add(new Object());
		a4.remove(2);
		a4.clear();
	}

第一段,因爲不存在類型約束,所以向集合內添加任何對象都不會報錯。
第二段,泛型是 Object ,也可以添加任何類型的對象,但唯一的區別是在進行類型轉化時會報錯的風險。
第三段,泛型是 Integer, 此時就有了約束,不是 Integer 類型的就無法成功添加其中
第四段, 添加通配符,只能進行 刪除和清理操作,不能進行添加操作。

我們可以發現,這幾種用法只能添加一種泛型約束,那有沒有添加多種泛型約束呢?

List<? extend> 與 List<? super> 的區別:
創建三個類,動物,狗,柯基。(柯基繼承狗,狗繼承動物):

        List<Animal> animal = new ArrayList<>();
		List<Dog> dog = new ArrayList<>();
		List<keji>kj = new ArrayList<>();
		
		animal.add(new Animal());
		dog.add(new Dog());
		kj.add(new keji());
		
		// 只能賦值給 Dog 和子類(keji),所以此時會報錯
		List<? extends Dog>extendsDogFromAnimal = animal;
		//只能賦值給 Dog 和父類
		List<? super Dog> superDogFromAnimal = animal;
		
		// 不能添加任何元素,會報錯
		extendsDogFromAnimal.add(new Dog());
		// 可以添加元素
		superDogFromAnimal .add(new Dog());
	 // 類型丟失,只能返回 對象類型
	  Object ob =	superDogFromAnimal.get(0);
	
	 //返回類型不會擦除,子類對象被擦除
	  Dog do = extendsDogFromAnimal.get(0);
		

通過上面的代碼可以發現,
List<?extends T>只能賦值給 自己和子類,上限是 T,不能添加元素,能返回父類和本類對象,但子類對象會被擦除。
List<? super T> 只能賦值自己和父類,下限是 T , 能添加元素,能返回 Object 類型的元素。

應用場景:
使用 <? extend T> 是 put 的功能受限,<? super T>是 get , 功能受限。
進行匿名投票時,向箱子裏投票,在想拿出來時就會被告知 “”您以參與投票!“”,而這裏就可以是使用 <? super T>
還可以拿上面的例子來說明 <?extend T> 適合放數據,<? super T>適合拿數據。

場景一: 當我們想放進一隻狗時,你會向哪個箱子選擇,是 動物箱子,還是狗箱子,抑或是 柯基箱子?
場景二: 當我們想拿出一隻動物時,你會向哪個箱子選擇,是 動物箱子,還是狗箱子,抑或是 柯基箱子?

總結:
花了些許的時間,介紹了 泛型,以及泛型和集合的聯合使用。看了一位大佬的視屏說如果你想提高編程能力,使代碼更富有條理性,利用 java 的泛型和反射 API 是最好的辦法。

發佈了50 篇原創文章 · 獲贊 58 · 訪問量 2421
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章