Java泛型是J2 SE1.5中引入的一個新特性,其本質(zhì)是參數(shù)化類型,也就是說所操作的數(shù)據(jù)類型被指定為一個參數(shù)(type parameter)這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口、泛型方法。1
提出背景Java集合(Collection)中元素的類型是多種多樣的。例如,有些集合中的元素是Byte類型的,而有些則可能是String類型的,等等。Java允許程序員構(gòu)建一個元素類型為Object的Collection,其中的元素可以是任何類型在Java SE 1.5之前,沒有泛型(Generics)的情況下,通過對類型Object的引用來實現(xiàn)參數(shù)的“任意化”,“任意化”帶來的缺點是要作顯式的強制類型轉(zhuǎn)換,而這種轉(zhuǎn)換是要求開發(fā)者對實際參數(shù)類型可以在預(yù)知的情況下進行的。對于強制類型轉(zhuǎn)換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現(xiàn)異常,這是一個安全隱患。因此,為了解決這一問題,J2SE 1.5引入泛型也是自然而然的了。1
發(fā)展概況Sun JDK的泛型發(fā)展要從1.3版本說起,他配合GJ,正式進入泛型殿堂。GJ是“Generic Java”的縮寫,是一個支援泛型的Java編譯器補充件,是Java泛型技術(shù)的先驅(qū)。隨后,泛型議題正式成為JSR#14,其技術(shù)基礎(chǔ)便是源自GJ。JDK1.4搭配JSR14提供的外掛附件,使泛型技術(shù)在Java世界成為眾所矚目的焦點。
2004年夏天,Sun公司發(fā)布了Java編程語言的重大修改版。該版本代號取名為“Tiger”,官方名稱為JDK1.5。JDK1.5相對于JDK1.3至JDK 1.4之間變化幅度大很多,它將在運行時性能(runtime performance)、可擴縮性(scalability)、易管理性(manageability)和監(jiān)控(monitoring)方面有較大加強;此外,還增加了許多激動人心的新的語言特性。泛型就是其中之一。JDK 1.5內(nèi)建泛型特征,不僅編譯器不再需要任何外力(外掛附件)的幫助,整個Java標(biāo)準(zhǔn)程式庫也被翻新,許多角落針對泛型做了改寫。2
作用**第一是泛化。**可以用T代表任意類型Java語言中引入泛型是一個較大的功能增強不僅語言、類型系統(tǒng)和編譯器有了較大的變化,以支持泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經(jīng)成為泛型化的了,這帶來了很多好處。
**第二是類型安全。**泛型的一個主要目標(biāo)就是提高ava程序的類型安全,使用泛型可以使編譯器知道變量的類型限制,進而可以在更高程度上驗證類型假設(shè)。如果不用泛型,則必須使用強制類型轉(zhuǎn)換,而強制類型轉(zhuǎn)換不安全,在運行期可能發(fā)生ClassCast Exception異常,如果使用泛型,則會在編譯期就能發(fā)現(xiàn)該錯誤。
**第三是消除強制類型轉(zhuǎn)換。**泛型可以消除源代碼中的許多強制類型轉(zhuǎn)換,這樣可以使代碼更加可讀,并減少出錯的機會。
**第四是向后兼容。**支持泛型的Java編譯器(例如JDK1.5中的Javac)可以用來編譯經(jīng)過泛型擴充的Java程序(Generics Java程序),但是現(xiàn)有的沒有使用泛型擴充的Java程序仍然可以用這些編譯器來編譯。1
泛型使用1、泛型類和泛型接口
如果定義的一個類或接口有一個或多個類型變量,則可以使用泛型。泛型類型變量由尖括號界定,放在類或接口名的后面,下面定義尖括號中的T稱為類型變量。意味著一個變量將被一個類型替代替代類型變量的值將被當(dāng)作參數(shù)或返回類型。對于List接口來說,當(dāng)一個實例被創(chuàng)建以后,T將被當(dāng)作一個函數(shù)的參數(shù)下面分別是泛型類、泛型接口的定義:
public class Gen{/泛型類……}public interface List extends Collection{//泛型接口……}2、泛型方法
是否擁有泛型方法,與其所在的類是否泛型無關(guān)。
要定義泛型方法,只需將泛型參數(shù)列表置于返回值前。
如:
public class ExampleA{ public voidf(Tx){ System.out.println(x.getClass().get Name()); } publiec static void main(String args[ ]){ ExampleA ea= new ExampleA(); ea-f(""); ea.f(10); ea.f(a); ea.f(ea); }}使用泛型方法時,不必指明參數(shù)類型,編譯器會自己找出具體的類型。泛型方法除了定義不同,調(diào)用就像普通方法一樣。需要注意,一個static方法,無法訪問泛型類的類型參數(shù),所以,若要static方法需要使用泛型能力,必須使其成為泛型方法。1
優(yōu)點Java語言中引入泛型是一個較大的功能增強。不僅語言、類型系統(tǒng)和編譯器有了較大的變化,以支持泛型,而且類庫也進行了很大的改動,許多重要的類,比如集合框架,都已經(jīng)成為泛型化的了。這帶來了很多好處:
1、類型安全
泛型的主要目標(biāo)是提高Java程序的類型安全。通過知道使用泛型定義的變量的類型限制,編譯器可以在非常高的層次上驗證類型假設(shè)。沒有泛型,這些假設(shè)就只存在于系統(tǒng)開發(fā)人員的頭腦中。
通過在變量聲明中捕獲這一附加的類型信息,泛型允許編譯器實施這些附加的類型約束。類型錯誤現(xiàn)在就可以在編譯時被捕獲了,而不是在運行時當(dāng)作ClassCastException展示出來。將類型檢查從運行時挪到編譯時有助于Java開發(fā)人員更早、更容易地找到錯誤,并可提高程序的可靠性。
2、消除強制類型轉(zhuǎn)換
泛型的一個附帶好處是,消除源代碼中的許多強制類型轉(zhuǎn)換。這使得代碼更加可讀,并且減少了出錯機會。盡管減少強制類型轉(zhuǎn)換可以提高使用泛型類的代碼的累贊程度,但是聲明泛型變量時卻會帶來相應(yīng)的累贊程度。在簡單的程序中使用一次泛型變量不會降低代碼累贊程度。但是對于多次使用泛型變量的大型程序來說,則可以累積起來降低累贊程度。所以泛型消除了強制類型轉(zhuǎn)換之后,會使得代碼加清晰和筒潔。
3、更高的運行效率
在非泛型編程中,將筒單類型作為Object傳遞時會引起B(yǎng)oxing(裝箱)和Unboxing(拆箱)操作,這兩個過程都是具有很大開銷的。引入泛型后,就不必進行Boxing和Unboxing操作了,所以運行效率相對較高,特別在對集合操作非常頻繁的系統(tǒng)中,這個特點帶來的性能提升更加明顯。
4、潛在的性能收益
泛型為較大的優(yōu)化帶來可能。在泛型的初始實現(xiàn)中,編譯器將強制類型轉(zhuǎn)換(沒有泛型的話,Java系統(tǒng)開發(fā)人員會指定這些強制類型轉(zhuǎn)換)插入生成的字節(jié)碼中。但是更多類型信息可用于編譯器這一事實,為未來版本的JVM的優(yōu)化帶來可能。3
使用注意事項使用ava泛型應(yīng)該注意如下幾點:
①在定義一個泛型類時,在“”之間定義形式類型參數(shù),例如:“class TestGen”,其中“K”,“V”不代表值,而是表示類型。
②實例化泛型對象時,一定要在類名后面指定類型參數(shù)的值(類型),一共要有兩次書寫。
③泛型中并不代表繼承,它是類型范圍限制。
④使用泛型時,泛型類型必須為引用數(shù)據(jù)類型,不能為基本數(shù)據(jù)類型,Java中的普通方法,構(gòu)造方法,靜態(tài)方法中都可以使用泛型,方法使用泛型之前必須先對泛型進行聲明,可以使用任意字母,一般都要大寫。
⑤不可以用一個本地類型(如int float)來替換泛型。
⑥運行時類型檢查,不同類型的泛型類是等價的(Pair與Pair是屬于同一個類型Pair),這一點要特別注意,即如果obj instance of Pai == true的話,并不代表objget First()的返回值是一個String類型。
⑦泛型類不可以繼承Exception類,即泛型類不可以作為異常被拋出。
⑧不可以定義泛型數(shù)組。
⑨不可以用泛型構(gòu)造對象,即:first = new T();是錯誤的。
⑩在static方法中不可以使用泛型,泛型變量也不可以用static關(guān)鍵字來修飾
?不要在泛型類中定義equals(Tx)這類方法,因為Object類中也有equals方法,當(dāng)泛型類被擦除后,這兩個方法會沖突。
?根據(jù)同一個泛型類衍生出來的多個類之間沒有任何關(guān)系,不可以互相賦值。
?若某個泛型類還有同名的非泛型類,不要混合使用,堅持使用泛型類。1
本詞條內(nèi)容貢獻者為:
徐恒山 - 博士 - 西北農(nóng)林科技大學(xué)