java泛型的一些總結
泛型引進的主要目的是:用來指定容器要持有什么樣類型的對象,而且由編譯器保證類型的正確性(編譯階段就能檢查出錯誤)。
泛型在java1.5之前并不存在,是在1.5的時候引入的,這說明之前的容器肯定有明顯的不足之處。
原生態類型容器的不足:
List list = new ArrayList();
list.add(new Apple());
list.add(new Dog());
list.add(new Person());
//從list中取出元素的時候,只能自己手工判斷了
if(list.get(1)instanceof Apple){
}elseif (list.get(1)instanceof Dog){
}else{
}
實際我們應用容器持有對象時,其實應該像使用數組一樣,可以指定所持有對象的數據類型。并且一個特定數組一般只持有一種數據類型的數據(包括該數據類型的子類)。
如
Fruit [] fruit = new Fruit[10];
fruit[0] = new Fruit();
fruit[1] = new Apple();
泛型因此被引入,以后可以用以下語句:
List<Fruit> fruitList = new ArrayList<Fruit>();
fuitList.add(new Fruit());
fuitList.add(new Apple());
按說此問題就應該都解決了,可是因為多態的存在,使得泛型產生了一系列問題。看下面的語句:
Fruit [] fruit = new Apple[10];
fruit[0] = new Apple();
fruit[1] = new Banana();
編譯時,類型檢查并沒有問題,但運行時此處的實際的fruit[]是Apple[],只能裝蘋果,現在讓他裝Banana,肯定不行。
還記得泛型的主要目的不?
重復一遍
用來指定容器要持有什么樣類型的對象,而且由編譯器保證類型的正確性
即泛型要在編譯階段解決這個不安全問題。
Java中的做法是讓:
List<Fruit> fruitList = new ArrayList<Apple>();在編譯階段報錯,這樣就成功解決了上述問題。但又產生了其他問題。
因為List<Fruit> fruitList = new ArrayList<Apple>();的直觀理解就是,你有一個fruit的容器,但是該容器不能放蘋果。你可以推斷該容器也不能放香蕉,橘子,葡萄,等等任何一種具體的水果。這顯然與常識不符。
但是你錯了,因為上述理解用的語句應該是:
List<Fruit> fruitList = new ArrayList<Fruit>();
而List<Fruit> fruitList = new ArrayList<Apple>();的正確理解是,fruitList是一個裝水果的容器,并不是裝水果容器(ArrayList<Apple>是裝蘋果的容器)的容器。
還有一個問題是我一會要去買一種特定的水果,具體是哪一種,只有到買的時候才能知道,現在要準備一個放該特定水果的容器,該怎么辦?
類似于List<Fruit> fruitList = new ArrayList<Fruit>();的語句不安全,存在最開始分析的手工判斷的缺點,
類似于List<Fruit> fruitList = new ArrayList<Apple>();在java中又不合法。
于是大牛們創造了:
List<? Extends Fruit> fruitList = new ArrayList<Apple>();
他們規定<? Extends Fruit>表示不是所有Fruit子類的集合,而是Fruit子類的任意的特定的一種。
體會任意的特定的一種的含義。
因為fruitList是任意的特定的一種水果,現在還不知道該種水果到底是哪一種,所以它不能add進去任何東西。
該類型的主要作用是給 fruitList賦值,然后從中取值。
接下來最讓人頭疼的問題來了:
泛型是1.5以后引入,在此之前的代碼應該在泛型引入以后還能用,所以jvm不能改,泛型只能是騙騙編碼的程序員,即泛型只是在編譯階段編譯器把一些強制類型轉換自動插入到你的代碼中,到運行階段時根本不存在任何關于泛型的痕跡。
泛型要是跟反射一起等運行時確定類型的一起方法一起使用時,我只想說 MLGB忘了泛型的存在吧,表面上的事都是騙人的,哥不干了。。。。