1.4 常用的泛型:使用泛型參數(shù)來編寫方法
Java5+
前面的小節(jié)介紹了泛型可以簡化Java代碼并使代碼能夠防范ClassCastException錯誤。除了作為JDK的一部分來使用泛型之外,還可以編寫你自己的泛型。當對類型相同的對象進行操作時泛型是很有用的,但是對象的具體類型直到對類實例化時才能知道。這種方式非常適合于包含關(guān)聯(lián)項目的集合或涉及查找的類。
下面編寫一個使用泛型參數(shù)的方法。回想一下前面是怎樣使用ArrayList類的—— 只在構(gòu)造ArrayList時才指定它使用哪些對象類型。注意,在定義類時并不知道其類型,并且不能將java.lang.Object作為類型使用,因為最后將遇到類似以前的類型強制轉(zhuǎn)換問題。當定義泛型時,必須使用一種特殊的語言來代表類型。當聲明類名時要完成此操作。在下面的示例中,<T>表示一種類將使用的類型:
public class RandomSelection<T> { } |
這里,類型指示符的尖括號看起來類似HTML語法,但實際上和HTML沒有關(guān)系,它們也不表示小于或大于!尖括號在一個泛型的類名與一個類型相結(jié)合的情況下使用,正如前面的ArrayList<Integer>那樣。盡管直到調(diào)用構(gòu)造函數(shù)時才知道真實的類型,但我們可以在方法定義中使用替換類型。假定定義了一個叫做RandomSelection的類,該類使用另一個類的某個類型,暫時將該類型稱為T。但是,此類的名字仍是RandomSelection。另外,每次可以對多個類型執(zhí)行這種操作,正如java.util.Map的定義所示的那樣。在這種情況下,在類名之后使用一個由逗號分隔的標識符列表即可。
public class MyGeneric<T,U,V> { } |
上面定義的MyGeneric類涉及到三個類型,它們分別稱為T、U和V。下面編寫一個方法來擴展RandomSelection類,該方法將一個項目添加到一個由內(nèi)部管理的泛型(類型為T)的ArrayList中:
public class RandomSelection<T> { |
注意,實際上并不是處理一個叫作T的類。T代表當某人創(chuàng)建RandomSelection的一個實例時使用的任意類。Java規(guī)范允許使用任意標識符,但是一般是使用單個大寫字母來和普通的類名進行區(qū)別。既然已經(jīng)定義add方法接受一個類型T參數(shù),則只能使用在構(gòu)造RandomSelection實例時采用的相同的類型來調(diào)用此方法。以下的代碼是非法的并會產(chǎn)生一個編譯錯誤:
RandomSelection<String> rs = new RandomSelection<String>(); |
如果希望一個方法返回一個泛型類型,可以將方法簽名的返回類型設(shè)為T,正如下面的定義所示:
import java.util.Random; |
getRandomElement方法返回一個類型T,即與在類聲明中定義的類型相同。通過構(gòu)造一個類型實例,現(xiàn)在可以使用剛才定義的RandomSelection類:
RandomSelection<Integer> selector = new RandomSelection<Integer>(); |
給一個整型變量choice賦值是安全的,因為selector的getRandomElement方法返回的總是一個Integer。情況確實如此,因為是使用Integer作為泛型類型來構(gòu)造的selector實例。Add和getRandomElement方法的定義具有和構(gòu)造函數(shù)的定義相同的類型,并且編譯器將會強制執(zhí)行此約束。嘗試在構(gòu)造函數(shù)中以一個不同的類型來使用RandomSelection類,這次使用前面定義的Fruit enum類:
RandomSelection<Fruit> fruitSelector = new RandomSelection<Fruit>(); |
可以看出,能夠直接使用來自getRandomElement方法的Fruit返回值,正如前面對待Integer那樣。如果你想要一個類與某種類型(直到構(gòu)造該類時才知道具體的類型)的對象協(xié)同操作以及希望編譯器嚴格執(zhí)行類型限制,那么你可以定義自己的泛型。這樣做的主要優(yōu)點體現(xiàn)在它的安全和便利性上。若想了解有關(guān)泛型的更多信息,請查閱網(wǎng)址http:// java.sun.com/j2se/1.5.0/docs/guide/language/generics.html上的Generics Tutorial(泛型指南) 和Java 5文檔。