沒有泛型的日子
所有的java類都源自java.lang.Object,這意味著所有的JAVA對象能轉(zhuǎn)換成Object。因此,在之前的JDK的版本中,很多集合框架的函數(shù)接受一個(gè)Object參數(shù)。所以,collections是一個(gè)能持有任何對象的多用途工具,但帶來了不良的后果。
舉個(gè)簡單的例子,在JDK 5.0的之前版本中,類List的函數(shù)add接受一個(gè)Object參數(shù):
成都創(chuàng)新互聯(lián)成都網(wǎng)站建設(shè)按需求定制網(wǎng)站,是成都網(wǎng)站建設(shè)公司,為成都電動(dòng)窗簾提供網(wǎng)站建設(shè)服務(wù),有成熟的網(wǎng)站定制合作流程,提供網(wǎng)站定制設(shè)計(jì)服務(wù):原型圖制作、網(wǎng)站創(chuàng)意設(shè)計(jì)、前端HTML5制作、后臺(tái)程序開發(fā)等。成都網(wǎng)站營銷推廣熱線:18982081108
所以你能傳遞任何類型給add。這是故意這么設(shè)計(jì)的。否則,它只能傳遞某種特定的對象,這樣就會(huì)出現(xiàn)各種List類型,如,StringList, EmployeeList, AddressList等。
add通過Object傳遞能帶來好處,現(xiàn)在我們考慮get函數(shù)(返回List中的一個(gè)元素).如下是JDK 5之前版本的定義:
get返回一個(gè)Object.不幸的事情從此開始了.假如你儲(chǔ)存了兩個(gè)String對象在一個(gè)List中:
當(dāng)你想從stringList1取得一個(gè)元素時(shí),你得到了一個(gè)Object.為了操作原來的類型元素,你不得不把它轉(zhuǎn)換為String。
但是,假如你曾經(jīng)把一個(gè)非String對象加入stringList1中,上面的代碼會(huì)拋出一個(gè)ClassCastException. 有了泛型,你能創(chuàng)建一個(gè)單一用途的List實(shí)例.比如,你能創(chuàng)建一個(gè)只接受String對象的List實(shí)例,另外一個(gè)實(shí)例只能接受Employee對象.這同樣適用于集合框架中的其他類型.
泛型入門
像一個(gè)函數(shù)能接受參數(shù)一樣,一個(gè)泛型也能接受參數(shù).這就是一個(gè)泛型經(jīng)常被稱為一個(gè)參數(shù)化類型的原因.但是不像函數(shù)用()傳遞參數(shù),泛型是用<>傳遞參數(shù)的.聲明一個(gè)泛型和聲明一個(gè)普通類沒有什么區(qū)別,只不過你把泛型的變量放在<>中.
比如,在JDK 5中,你可以這樣聲明一個(gè)java.util.List : List
E 稱為類型變量.意味著一個(gè)變量將被一個(gè)類型替代.替代類型變量的值將被當(dāng)作參數(shù)或返回類型.對于List接口來說,當(dāng)一個(gè)實(shí)例被創(chuàng)建以后,E 將被當(dāng)作一個(gè)add或別的函數(shù)的參數(shù).E 也會(huì)使get或別的參數(shù)的返回值.下面是add和get的定義:
一個(gè)泛型在聲明或例示時(shí)允許你傳遞特定的類型變量: E.除此之外,如果E是個(gè)類,你可以傳遞子類;如果E是個(gè)接口,你可以傳遞實(shí)現(xiàn)接口的類;
-----------------------------譯者添加--------------------
那么mylist的add函數(shù)將接受一個(gè)String作為他的參數(shù),而get函數(shù)將返回一個(gè)String.因?yàn)榉祷亓艘粋€(gè)特定的類型,所以不用類型轉(zhuǎn)化了。
根據(jù)慣例,我們使用一個(gè)唯一的大寫字目表示一個(gè)類型變量。為了創(chuàng)建一個(gè)泛型,你需在聲明時(shí)傳遞同樣的參數(shù)列表。比如,你要想創(chuàng)建一個(gè)ArrayList來操作String ,你必須把String放在<>中。如:
再比如,java.util.Map 是這么定義的:
public interface Map
K用來聲明map鍵(KEY)的類型而V用來表示值(VALUE)的類型。put和values是這么定義的:
V put(K key, V value)
Collection
一個(gè)泛型不準(zhǔn)直接的或間接的是java.lang.Throwable的子類。因?yàn)楫惓J窃谶\(yùn)行時(shí)拋出的,所以它不可能預(yù)言什么類型的異常將在編譯時(shí)拋出.
列表1的例子將比較List在JDK 1.4 和JDK1.5的不同
在列表1中,stringList2是個(gè)泛型。聲明List
泛型的類型檢查(type checking)是在編譯時(shí)完成的.
最讓人感興趣的事情是,一個(gè)泛型是個(gè)類型并且能被當(dāng)作一個(gè)類型變量。比如,你想你的List儲(chǔ)存lists of Strings,你能通過把List
要從myList中的第一個(gè)List重新取得String,你可以這么用:
下一個(gè)列表中的ListOfListsTest類示范了一個(gè)List(命名為listOfLists)接受一個(gè)String List作為參數(shù)。
另外,一個(gè)泛型接受一個(gè)或多個(gè)類型變量。比如,java.util.Map有兩個(gè)類型變量s。第一個(gè)定義了鍵(key)的類型,第二個(gè)定義了值(value)的類型。下面的例子講教我們?nèi)绾问褂脗€(gè)一個(gè)泛型Map.
在這個(gè)例子中,重新得到一個(gè)key1代表的String值,我們不需要任何類型轉(zhuǎn)換。