黑馬程序員--java高新技術----泛型

---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------


jdk1.5加入了泛型這一概念。

泛型:用於解決安全問題,是一個安全機制。

好處:

        1.把原本的運行時會出現的類型轉換異常(ClassCastException),轉移到程序編譯時期,方便程序員解決問題,讓運行時期的問題減少,提高程序的安全性。

        2.避免了強制類型轉換的麻煩。

        3.實現模板設計模式

通過一個例子瞭解泛型:




這個程序中向集合中添加數據,前三個添加的是字符串,最後一個添加的是整數。

編譯時並不會出現問題,但是運行時會出現類型轉換異常。



使用泛型:




使用泛型,把集合所存儲的數據類型事先規定好。所以在程序中如果有其他類型的數據,編譯就不會通過。





不過在實驗中我發現,現在的java版本已經會自動把整數轉換爲字符串,所以如果使用的jdk版本高的話,在集合中存入整數可能不會出現問題。

但是通過另一中途徑一定可以發現問題。




在這個程序中我直接存了一個對象到集合中,編譯也不會出錯,不過運行時出現了類型轉換異常(java.lang.ClassCastException)。


這樣,使用泛型的好處就一目瞭然了。程序員不注意可能會在存放字符串的集合中存入整數,編譯時可能不會出現問題,一位程序可以用了就完事了,但是運行時會出現問題。如果存數據的動作由用戶完成,程序員沒有提供數據類型這個問題,用戶在使用是出現了問題,那就麻煩了。


通過上面的列子可以看到泛型的作用。

那麼,java中什麼時候使用泛型呢?

通常在集合框架中很常見,因爲集合是存放對象的,不想數組那樣,在定義一個數組時就把數組的長度,類型都定義好了,集合都沒有定義,所以使用泛型可以規定集合存放的數據類型。


通過查看Collection接口的API文檔可以發現:


接口 Collection<E>


方法摘要
boolean add(E e)
確保此 collection 包含指定的元素(可選操作)。

注意Collection後面的<E>就是使用泛型,而在add()方法中,參數也規定爲(E e)。


到這裏基本可以理解反省的使用方法了,拿集合來說:

<>是泛型的標誌,<>裏面的內容是要存入集合的數據的類型,把類型以參數的方式傳遞給集合類。


泛型在比較器中也用到。

java.util
接口 Comparator<T>

類型參數:
T - 此 Comparator 可以比較的對象類型
方法摘要
int compare(T o1, T o2)
比較用來排序的兩個參數。

舉個例子來看看 Comparator接口所使用到的泛型。

按照字符串的長度進行比較。



Comparator接口可以比較不同對象的同一屬性,比如比較兩個學生的年齡大小,但是不能比較一個學生的年齡和另一個學生的姓名的大小。

這也可以理解爲什麼Comparator接口要用到泛型。


自己也可以寫泛型類,模仿集合接口使用泛型的方法即可。

泛型也稱爲模板或參數多肽,既是模板,就應該有模板的特性,下面通過自己我寫的一個泛型類來體現泛型的模板特性。



通過程序可以看到,utils類爲泛型類,在utils類中定義了show()方法,參數爲T類型。

main()方法中既可以傳遞字符串參數給show()方法,也可以傳遞Integer參數給show()方法,這樣就不用分別爲字符串和整型參數寫不同的show()方法,這就體現出了模板的特性。


而且當給泛型類傳遞了數據類型參數後,就規定了泛型類對象所能接受的參數類型,如果傳遞的參數類型爲其他類型,則編譯不會通過,而不用泛型,編譯時可以通過的。




因爲在確定了數據類型爲String類型後,又傳遞了整型和Object類型的參數,所以編譯不通過。

這就體現了泛型的安全性特點。


除了定義泛型類,還可以定義泛型方法,反省方法的操作性更靈活,因爲定義泛型類的話,整個類裏面的方法接收的參數類型都是一致的,而定義泛型方法,則方法可以接收不同類型的數據。


泛型方法的定義格式:

        public <T> void show(T  t)
{
System.out.println(t);
}

使用時給改方法傳遞任何類型的參數都可以。




那麼,可以在泛型類中再定義泛型方法嗎?

會出錯嗎?

哪個優先級更高?

猜是猜不出來的,試試就知道了。




定義泛型方法時,參數類型<T>應該放在返回類型符前面,修飾符後面。

public static <T> void show(T  t){ } ;


再看下面一個例子:

Student類繼承Person類,把Person對象和Student對象分別存入集合中,然後調用泛型方法printAll()打印。






如果使用反省方法打印的話,那麼任意類型的對象都可以打印。

而如果只想讓繼承Person類的對象纔可以使用打印方法打印,那些非Person繼承類的對象不能打印,能否實現呢?答案是能。


這就要用到泛型限定。

語法是這樣的:


                              ArrayList<? extends Person>


?是通配符,參數不是單單一個了,而是一個繼承語句。





當給泛型方法printAll()傳遞非Person()子類對象作爲參數是,編譯就會報錯,就不能使用該泛型方法。


這就完成了泛型限定,只有Person子類的對象纔可以使用此泛型方法。


反省最重要的兩個特點:

1. 安全

2. 模板


記住這兩個特點,再去學習泛型就明白,所有泛型的使用都是爲了實現這兩個特性。




---------------------- ASP.Net+Android+IOS開發.Net培訓、期待與您交流! ----------------------

   詳細請查看 www.itheima.com


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