Jdk1.5新特性之泛型(-)

Jdk1.5新特性之泛型(-)

1.泛型的概念:是一種把類型明確的工作推遲到創建對象或者調用方法的時候纔去明確的特殊的類型。參數化類型,把類型當作參數一樣的傳遞。“泛型”這個術語意思是:適用於許多許多的類型。

2.爲什麼要使用泛型?

 有許多原因使得泛型的出現,而最重要的一個原因就是爲了更好的創造容器類(java的集合類)。容器,顧名思義,就是一個存儲東西的地方。我們以前所學的數組就是一個容器,不過與數組相比,容器類更加的靈活,具備更多的功能。但是容器類有個缺點:當我們把一個對象放進容器後,容器就會“忘記”該對象的數據類型,當取出該對象時,該對象的編譯類型就被當做Object來處理(運行類型不變)。Java的開發人員把它設計成這樣是爲了更好地通用性。但是這樣做也就會有兩個問題:

1.容器對裝入對象的類型沒有任何限制,也就是說,你可以向這個容器中放入Dog對象,同時你還可以向這個容器中放入Cat對象,那麼問題來了,當你取得時候就可能發生異常了。

2.因爲把對象放入容器類後,該對象類型信息被丟失,容器只知道它自己裝的類型是Object的,也就是說所有東西都是Object的,所以取對象時還需要強制類型轉換,這樣子做不僅會增加編程的複雜度,而且有時還會出現ClassCastException。

 

看一下代碼:

@SuppressWarnings({ "rawtypes""unchecked" })

public static void main(String[] args) {

List list = new ArrayList();

list.add("love java");

list.add("love 生活");

list.add(23);

for(Object objL:list){

 String s=(String)objL;

 System.out.println(s);

}

}

當運行後就會出現異常:

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

 

從某種意義上說,最簡單的容器數組這一點還是做得很好的(當然Object類型數組除外),因爲數組類型是確定裝入某種類型的。

3.手動實現編譯時檢查類型

我們可以看見容器在編譯時是不區分類型的,如果你希望給某一個容器添加的固定類型的對象,那麼我們可以自己做編譯檢查,看一下代碼:

import java.util.ArrayList;

import java.util.List;

 

public class AddStr { 

 

@SuppressWarnings("rawtypes")

private List list = new ArrayList();

 

@SuppressWarnings("unchecked")

public boolean add(String ele){

return list.add(ele);

}

public String get(int index){

return (String)list.get(index);

}

public int size(){

return list.size();

}

}

這是自己定義的一個添加字符串的容器,其實根本沒做什麼,都是ArrayList做的事情,下面看測試代碼:

 

 

 

我們可以看到,當你試圖添加非字符串對象時,那麼編譯就不會通過,這是因爲我們自己定義的容器類的add方法對ArrayList的add方法做了個封裝,也就限定該容器只能裝字符串對象了。同時,在CheckPyte類中,我推薦了幾本學習java的書籍。

從健壯性角度上看,這種方式還是很有用的,在編譯時就做到了類型的檢查了。這種做法雖然有效,但侷限性很明顯,我們需要定義大量的這種類來封裝list對象。

 

4.引入泛型

 泛型的格式:  <數據類型>

 注意:此處的數據類型只能是引用類型。

利用泛型,使得List集合只能裝字符串對象,看下面代碼:

 

我們可以看到泛型就是在List基礎上加了一個<String>,這就是使用了泛型了,表示這個List集合只能存放String,不能存放其他,並且從這個集合取出元素時,也不需要進行強制轉換了。上面的代碼不僅更加健壯,程序再也不能“不小心”的把其他對象“丟進”list集合中了。而且程序更加簡潔,集合自動記住集合元素類型,所以沒必要對集合元素強制類型轉化了。

 

5.泛型中的一些術語

 在jdk幫助文檔中我們經常看到使用泛型的一些類,比如:ArrayList<E>,還有我們定義過的ArrayList<Integer>;

(1)整個稱爲ArrayList<E>泛型類型。

(2)ArrayList<E>中的E稱爲類型變量或類型參數,並且這個E只能是引用類型。

(3)整個ArrayList<Integer>稱爲參數化的類型。

(4)ArrayList<Integer>中的Integer稱爲實際類型參數。

(5)ArrayList<Integer>中的<>讀作type。

(6)ArrayList稱爲原始類型。

 

7.我們從上面的代碼中也可以看出參數化類型和原始類型是兼容的,不過編譯器報告警告。如:

Collection<Stringcoll=new ArrayList();

Collection coll2=new ArrayList<String>();

 

在這裏值得注意的是:參數化類型不考慮類型參數的繼承關係,也就是說 ArrayList<Object> list = new ArrayList<String>;這樣是錯誤的。類型參數嚴格說明集合中裝入數據類型是什麼和可以加入什麼類型的數據,要記住的是:ArrayList<Object> 和ArrayList<String>是沒有轉換關係的參數化類型。

我們來分析一下爲什麼不能考慮繼承:

如果ArrayList<Object> list = new ArrayList<String>;這句話成立的話,那麼ArrayList<Object> list就是說可以向list裝入任何對象,然而右邊ArrayList<String>表明實際上指向的集合只能裝String類型對象,這樣也就矛盾了。

對象使用泛型,還有一點也值得注意:泛型與數組不能一起使用,也就是說Vector<Integer> [] vector = new Vector<Integer>[5];這樣做是錯誤的。

下面我們來看看一個小小的思考題:

ArrayList list = new ArrayList<Stirng>;  ①

ArrayList<Object> arrObj = list;    ②

那麼,這兩句代碼在編譯期會不會報錯呢?

實際上編譯器不會報錯,第一條把參數化類型給原始類型不會報錯,第二句把原子類型給參數化類型也不會報錯。我們不能把兩句連起來看,因爲編譯器一句一句的執行,是一個嚴格按語法檢查的工具,不考慮運行時的效果。

 

還有其他的泛型知識,在下一章會給出。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章