java開發(fā)技術(shù)大全第10章 泛型_第1頁
java開發(fā)技術(shù)大全第10章 泛型_第2頁
java開發(fā)技術(shù)大全第10章 泛型_第3頁
java開發(fā)技術(shù)大全第10章 泛型_第4頁
java開發(fā)技術(shù)大全第10章 泛型_第5頁
已閱讀5頁,還剩20頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、第 10 章泛型泛型是 JDK1.5 中新加入的元素,它改變了核心 API 中的許多類和方法。使用泛型, 可以建立以類型安全模式處理各種數(shù)據(jù)的類、接口和方法。許多算法不論運用哪一種數(shù)據(jù)類型,它們在邏輯上是一樣的。使用泛型,一旦定義了一個算法,就獨立于任何特定的數(shù)據(jù)類型,而且不需要額外的操作,就可以將這個算法應用到各種數(shù)據(jù)類型中。正由于泛型的強大功能,從根本上改變了 Java 代碼的編寫方式。 本章將介紹泛型的語法和應用,同時展示泛型如何提供類型安全。 10.1泛型的本質(zhì)泛型在本質(zhì)上是指類型參數(shù)化。所謂類型參數(shù)化,是指用來聲明數(shù)據(jù)的類型本身,也是可以改變的,它由實際參數(shù)來決定。在一般情況下,實際

2、參數(shù)決定了形式參數(shù)的值。而類型參數(shù)化,則是實際參數(shù)的類型決定了形式參數(shù)的類型。 舉個簡單的例子。方法 max()要求返回兩個參數(shù)中較大的那個,可以寫成: 這樣編寫代碼當然沒有問題。不過,如果需要比較的不是 Integer 類型,而是 Double 或是 Float 類型,那么就需要另外再寫 max()方法。參數(shù)有多少種類型,就要寫多少個 max() 方法。但是無論怎么改變參數(shù)的類型,實際上 max()方法體內(nèi)部的代碼并不需要改變。如果有一種機制,能夠在編寫 max()方法時,不必確定參數(shù) a 和 b 的數(shù)據(jù)類型,而等到調(diào)用的時候再來確定這兩個參數(shù)的數(shù)據(jù)類型,那么只需要編寫一個 max()就可以

3、了,這將大大降低程序員編程的工作量。 在 C+中,提供了函數(shù)模板和類模板來實現(xiàn)這能。而從 JDK1.5 開始,也提供了類似的機制:泛型。從形式上看,泛型和 C+的模板很相似,但它們是采用完全不同的技術(shù)來實現(xiàn)的。 在泛型出現(xiàn)之前,Java 的程序員可以采用一種變通的辦法:將參數(shù)的類型均聲明為Object 類型。由于 Object 類是所有類的父類,所以它可以指向任何類對象,但這樣做不能保證類型安全。 泛型則彌補了上述做法所缺乏的類型安全,也簡化了過程,不必顯示地在 Object 與實 際操作的數(shù)據(jù)類型之間進行強制轉(zhuǎn)換。通過泛型,所有的強制類型轉(zhuǎn)換都是自動和隱式的。 Integer max(Int

4、eger a, Integer b) return ab?a:b;第 10 章 泛型 因此,泛型擴展了重復使用代碼的能力,而且既安全又簡單。10.2一個關(guān)于泛型的簡單例子這里用一個簡單的例子來開始泛型的學習,讓讀者對泛型有一個感性的認識?!纠?10.1】 泛型類示例。 /-文件名 Generic.java,程序編號 10.1-下面這個程序使用上面這個泛型類。 /-文件名 demoGeneric.java,程序編號 10.2-305public class demoGenericpublic static void main(String args)/聲明一個 Integer 類型的 Gener

5、ic 變量 Generic iobj;/創(chuàng)建一個 Integer 類型的 Generic 對象 iobj = new Generic(100);/輸出它的一些信息iobj.showType();int k = iobj.getOb(); System.out.println(k=+k);/聲明一個 String 類型的 Generic 變量 Generic sobj;/創(chuàng)建一個 Double 類型的 Generic 對象 sobj = new Generic(Hello);/輸出它的一些信息sobj.showType();String s = sobj.getOb(); System.out.

6、println(s=+s);/聲明一個泛型類 public class GenericT ob; /ob 的類型是 T,現(xiàn)在不能具體確定它的類型,需要到創(chuàng)建對象時才能確定Generic(T o) ob = o;/這個方法的返回類型也是 T T getOb()return ob;/顯示 T 的類型 void showType()System.out.println(Type of T is:+ob.getClass().getName() );Java 開發(fā)技術(shù)大全程序的輸出結(jié)果如下:下面來仔細分析一下這個程序。 首先,注意程序是如何聲明 Generic 的: public class Gene

7、ric其中,T 是類型參數(shù)的名稱。在創(chuàng)建一個對象時,這個名稱用作傳遞給 Generic 的實際類型的占位符。因此,在 Generic 中,每當需要類型參數(shù)時,就會用到 T。注意,T 是被括在“”中的。每個被聲明的類型參數(shù),都要放在尖括號中。由于 Generic 使用了類型參數(shù),所以它是一個泛型類,也被稱為參數(shù)化類型。 然后,T 來聲明了一個成員變量 ob: T ob;由于 T 只是一個占位符,所以 ob 的實際類型要由創(chuàng)建對象時的參數(shù)傳遞進來。比如, 傳遞給 T 的類型是 String,那么 ob 就是 String 類型。 最后,看一下 Generic 的構(gòu)造方法: 它的參數(shù) o 的類型也是

8、 T。這意味著 o 的實際類型,是由創(chuàng)建 Generic 對象時傳遞給 T 的類型來決定的。而且,由于參數(shù) o 和成員變量 ob 都是 T 類型,所以無論實際類型是什么,二者都是同一個實際類型。 參數(shù) T 還可以用來指定方法的返回類型,如下所示: 因為 ob 是 T 類型,所以方法的返回類型必須也由 T 來指定。 showType()方法通過使用 Class 對象來獲取 T 的實際類型,這就是第 9 章介紹的 RTTI 機制。 綜合上面的用法,可以看出,T 是一個數(shù)據(jù)類型的說明,它可以用來說明任何實例方法中的局部變量、類的成員變量、方法的形式參數(shù)以及方法的返回值。 注意:類型參數(shù) T 不能使用

9、在靜態(tài)方法中。 程序 9.2 示范了如何使用一個泛型類 Generic。它首先聲明了 Generic 的一個整型版本: Generic iobj;306TgetOb() r eturn ob;Generic(To) ob = o;Type of T is:java.lang.Integer k=100Type of T is:java.lang.Strings=Hello第 10 章 泛型 其中,類型 Integer 被括在尖括號內(nèi),表明它是一個類型實際參數(shù)。在這個整型版本中, 所有對 T 的引用都會被替換為 Integer。所以 ob 和 o 都是 Integer 類型,而且方法 getOb

10、() 的返回類型也是 Integer 類型的。 注意 Java 的編譯器并不會創(chuàng)建多個不同版本的 Generic 類。相反,編譯器會刪除所有的泛型信息,并進行必要的強制類型轉(zhuǎn)換,這個過程被稱為擦拭或擦除。但對程序員而言, 這一過程是透明的,仿佛編譯器創(chuàng)建了一個 Generic 的特定版本。這也是 Java 的泛型和 C+ 的模板類在實現(xiàn)上的本質(zhì)區(qū)別。 下面這條語句真正創(chuàng)建了一個 Integer 版本的實例對象: 其中,100 是普通參數(shù),Integer 是類型參數(shù),它不能被省略。因為 iobj 的類型是 Generic,所以用 new 返回的引用必須是 Generic類型。無論是省略 Inte

11、ger,還是將其改成其他類型,都會導致編譯錯誤。例如: 因為 iobj 是 Generic類型,它不能引用 Generic對象。泛型的一個好處就是類型檢查,所以它能確保類型安全。 再回顧一下 Generic 的構(gòu)造方法的聲明: 其中,實際參數(shù)應該是 Integer 類型,而現(xiàn)在的實際參數(shù) 100 是 int 型,這似乎不正確。實際上,這里用到了 Java 的自動裝箱機制(將在 12.3 節(jié)中介紹)。當然,創(chuàng)建對象也可以寫成這種形式: 但這樣寫沒有任何必要。 然后,程序通過下面的語句獲得 ob 的值:注意,getOb 的返回類型也是 Integer 的。當它賦值給一個 int 變量時,系統(tǒng)會自動

12、拆箱,所以沒有必要這么來寫: 后面創(chuàng)建 String 版本的過程和前面的完全一樣,在此不再贅述。 最后還有一點需要讀者特別注意:聲明一個泛型實例時,傳遞給形參的實參必須是類類型,而不能使用 int 或 char 之類的簡單類型。比如不能這樣寫: 如果要使用簡單類型,只能使用它們的包裝類,這也是泛型和 C+模板的一個重要 區(qū)別。 307Generic ob = new Generic (100); /錯誤 int k = iobj.getOb().intValue();int k = iobj.getOb();iobj = new Generic(new Integer(100);Generic

13、(T o)iobj = new Generic(1.234); /錯誤 iobj = new Generic(100);Java 開發(fā)技術(shù)大全10.3帶兩個類型參數(shù)的泛型類在泛型中,可以聲明一個以上的類型參數(shù),只需要在這些類型參數(shù)之間用逗號隔開。下面看一個簡單的例子。 【例 10.2】 帶兩個類型參數(shù)的泛型。 /-文件名 twoGen.java,程序編號 10.3-下面這個程序演示流如何使用上面這個泛型類。 /-文件名 simpGen.java,程序編號 10.4-程序的輸出結(jié)果如下:308public class simpGenpublic static void main(Stringar

14、gs) twoGen tgObj;/指定類型參數(shù)的實際類型 /構(gòu)造方法中需要再次指定類型參數(shù),同時還要傳遞實際參數(shù)tgObj = new twoGen(100,Hello); tgObj.showTypes();int v = tgObj.getOb1(); System.out.println(value: +v); String str = tgObj.getOb2(); System.out.println(value: +str);/本類帶有兩個類型參數(shù) public class twoGenT ob1; V ob2;/構(gòu)造方法也可以使用這兩個類型參數(shù) twoGen(T o1, V o

15、2) ob1 = o1; ob2 = o2;/顯示 T 和 V 的類型 void showTypes()System.out.println(Type of T is +ob1.getClass().getName(); System.out.println(Type of V is +ob2.getClass().getName(); TgetOb1() r eturn ob1; VgetOb2() return ob2;第 10 章 泛型 與只有一個類型參數(shù)的泛型相比,本例并沒有什么難于理解的地方。Java 并沒有規(guī)定這兩個類型參數(shù)是否要相同,比如,下面這樣來創(chuàng)建對象也是可以的: 這樣 T

16、 和 V 都是 String 類型,這個例子并沒有錯。但如果所有的實例都是如此,就沒 有必要用兩個參數(shù)。 10.4有 界 類 型在前面的例子中,參數(shù)類型可以替換成類的任意類型。在一般情況下,這是沒有問題的,但有時程序員需要對傳遞給類型參數(shù)的類型加以限制。 比如,程序員需要創(chuàng)建一個泛型類,它包含了一個求數(shù)組平均值的方法。這個數(shù)組的類型可以是整型、浮點型,但顯然不能是字符串類型或是其他非數(shù)值類型。如果程序員寫出如下所示的泛型類。 /-文件名 Stats.java,程序編號 10.5-其中,numsi.doubleValue()是返回 Ingeger、Double 等數(shù)據(jù)封裝類轉(zhuǎn)換成雙精度數(shù)后的值,

17、所有的 Number 類的子類都有這個方法。但問題是,編譯器無法預先知道,程序員的意圖是只能使用 Number 類來創(chuàng)建 Stats 對象,因此,編譯時會報告找不到 doubleValue() 方法。 為了解決上述問題,Java 提供了有界類型(bounded types)。在指定一個類型參數(shù)時, 可以指定一個上界,聲明所有的實際類型都必須是這個超類的直接或間接子類。語法形式如下: 309class classname classStats T nums;Stats (T obj) nums = obj;doubleaverage() double sum = 0.0;for (int i=0

18、; inums.length; +i)sum += numsi.doubleValue();/這里有錯誤! twoGentgObj=newtwoGen (Hello,World);Type of T is java.lang.Integer Type of V is java.lang.String value: 100value: HelloJava 開發(fā)技術(shù)大全采用這種方法,可以正確地編寫 Stats 類。 【例 10.3】 有界類型程序示例。 /-文件名 Stats.java,程序編號 10.6-程序 10.7 演示了如何使用這個類。 /-文件名 demoBounds.java,程序編號

19、 10.7-程序的輸出結(jié)果如下:程序 10.6 和程序 10.7 的上界都是類,實際上,接口也可以用來做上界。比如: class Stats注意:這里使用的關(guān)鍵字仍然是 extends 而非 implements。一個類型參數(shù)可以有多個限界,比如: class Stats310平均值為:3.0 平均值為:3.3public class demoBoundspublic static void main(String args) Integer inums =1,2,3,4,5;Stats iobj = new Stats(inums); System.out.println( 平 均 值 為

20、:+iobj.average(); Double dnums = 1.1,2.2,3.3,4.4,5.5;Stats dobj = new Stats(dnums); System.out.println(平均值為:+dobj.average();/如果像下面這樣創(chuàng)建 String 類型的對象將無法編譯通過 /String snums = 1,2,3,4,5;/Stats sobj = new Stats(snums);/System.out.println(平均值為:+sobj.average();/下面這個泛型的實際類型參數(shù)只能是 Number 或它的子類 class Stats T nu

21、ms; Stats (T obj) nums = obj;doubleaverage() double sum = 0.0;for (int i=0; inums.length; +i)sum += numsi.doubleValue();/現(xiàn)在正確! return sum / nums.length;第 10 章 泛型 注意:限界類型用“&”分隔,因為逗號用來分隔類型參數(shù)。在多個限界中,可以有多個接口,但最多只能有一個類。如果用一個類作為限界,它必須是限界列表中的第一個。 10.5通配符參數(shù)前面介紹的泛型已經(jīng)可以解決大多數(shù)的實際問題,但在某些特殊情況下,仍然會有一些問題無法輕松地解決。 以

22、Stats 類為例,假設(shè)在其中存在一個名為 doSomething()的方法,這個方法有一個形式參數(shù),也是 Stats 類型,如下所示: 如果在使用的時候,像下面這樣寫是有問題的:注意看出現(xiàn)錯誤的這條語句:dobj.doSomething(iobj);dobj 是 Stats類型,iobj 是 Stats類型,由于實際類型不同,而聲明時 用的是: void doSomething(Stats ob)它的類型參數(shù)也是 T,與聲明對象時的類型參數(shù) T 相同。于是在實際使用中,就要求 iobj 和 dobj 的類型必須相同。 讀者也許會想,將 doSomething 的聲明改一下: void doS

23、omething(Stats ob)但這樣是無法通過編譯的,因為并不存在一個 State的泛型類。解決這個問題的辦法是使用 Java 提供的通配符“?”,它的使用形式如下: genericClassName 比如,上面的 doSomething 可以聲明成這個樣子:311Integer inums = 1,2,3,4,5;Stats iobj = new Stats(inums); Double dnums = 1.1,2.2,3.3,4.4,5.5;Stats dobj = new Stats(dnums); dobj.doSomething(iobj); /錯誤 class Stats v

24、oid doSomething(Stats ob) System.out.println(ob.getClass().getNam e();Java 開發(fā)技術(shù)大全void doSomething(Stats ob)它表示這個參數(shù) ob 可以是任意的 Stats 類型,于是調(diào)用該方法的對象就不必和實際參數(shù)對象類型一致了。下面這個例子實際演示了通配符的使用。 【例 10.4】 通配符使用示例。 /-文件名 Stats.java,程序編號 10.8-然后如程序 10.9 所示來調(diào)用它: /-文件名 demoWildcard.java,程序編號 10.9-程序的輸出結(jié)果如下:Stats讀者應該注意到這

25、個聲明:void doSomething(Stats ob) /這里使用了類型通配符 它與泛型類的聲明有區(qū)別,泛型類的聲明中,T 是有上界的:class Stats其中,通配符“?”有一個默認的上界,就是 Number。如果想改變這個上界,也是可以的,比如: Stats ob312public class demoWildcard public static void main(Stringargs) Integer inums =1,2,3,4,5;Stats iobj = new Stats(inums); Double dnums = 1.1,2.2,3.3,4.4,5.5;Stats

26、dobj = new Stats(dnums); dobj.doSomething(iobj);/iobj 和 dobj 的類型不相同 class Stats T nums; Stats (T obj) nums = obj;doubleaverage() double sum = 0.0;for (int i=0; inums.length; +i) sum += numsi.doubleValue();return sum / nums.length;void doSomething(Stats ob) /這里使用了類型通配符System.out.println(ob.getClass()

27、.getName();第 10 章 泛型 但是不能寫成這樣:因為 Integer 是 Number 的子類,而 String 不是 Number 的子類。通配符無法將上界改變得超出泛型類聲明時的上界范圍。 最后讀者需要注意一點,通配符是用來聲明一個泛型類的變量的,而不能創(chuàng)建一個泛型類。比如下面這種寫法是錯誤的: 10.6泛 型 方 法在 C+中,除了可以創(chuàng)建模板類,還可以創(chuàng)建模板函數(shù)。在 Java 中也提供了類似的功能:泛型方法。一個方法如果被聲明成泛型方法,那么它將擁有一個或多個類型參數(shù),不過與泛型類不同,這些類型參數(shù)只能在它所修飾的泛型方法中使用。 創(chuàng)建一個泛型方法常用的形式如下: 訪問權(quán)

28、限修飾符(包括 private、public、protected)、static 和 final 都必須寫在類型參數(shù)列表的前面。 返回值類型必須寫在類型參數(shù)表的后面。 泛型方法可以寫在一個泛型類中,也可以寫在一個普通類中。由于在泛型類中的任何方法,本質(zhì)上都是泛型方法,所以在實際使用中,很少會在泛型類中再用上面的形式來定義泛型方法。 類型參數(shù)可以用在方法體中修飾局部變量,也可以用在方法的參數(shù)表中,修飾形式參數(shù)。 泛型方法可以是實例方法或是靜態(tài)方法。類型參數(shù)可以使用在靜態(tài)方法中,這是 與泛型類的重要區(qū)別。 使用一個泛型方法通常有兩種形式:和:如果泛型方法是實例方法,要使用對象名作為前綴。如果是靜態(tài)

29、方法,則可以使用對象名或類名作為前綴。如果是在類的內(nèi)部調(diào)用,且采用第二種形式,則前綴都可以省略。注意到這兩種調(diào)用方法的差別在于前面是否顯示地指定了實際類型。是否要使用實際類型,需要根據(jù)泛型方法的聲明形式以及調(diào)用時的實際情況(就是看編譯器能否從實際參數(shù)表中獲得足夠的類型信息)來決定。下面來看一個例子。 313對象名|類名.方法名(實際參數(shù)表);.方法名(實際參數(shù)表);訪問權(quán)限修飾符 static final 返回值類型 方法名(形式參數(shù)列表)class StatsStats obJava 開發(fā)技術(shù)大全【例 10.5】 泛型方法使用示例。 /-文件名 demoGenMethods.java,程序編

30、號 10.10-程序中定義的兩個泛型方法都是靜態(tài)方法,這在泛型類中是不允許的。而且這兩個泛型方法相互重載(參數(shù)的個數(shù)不同)。在方法體中,類型參數(shù) T 的使用和泛型類中的使用是相同的。 再來看看如何調(diào)用這兩個泛型方法: 在第一種調(diào)用形式中,傳入了一個實際類型:,它表明類型參數(shù)是 Integer類型。要注意它的寫法,在這種情況下,不能省略作為前綴的類名,也就是不能寫成這樣: showGenMsg(k,1);由于傳遞了一個實際的類型參數(shù) Integer,所以編譯器知道如何將方法內(nèi)部的占位符 T 替換掉。不過需要注意,實際參數(shù) k 的類型必須也是 Integer 型,否則編譯器會報錯。第二種調(diào)用形式明

31、顯要簡潔一些: showGenMsg(str);由于實參 str 是 String 類型的,編譯器已經(jīng)有了足夠多的信息知道類型參數(shù) T 是 String類型。程序的輸出結(jié)果如下: 由于兩種形式都能完成任務,而第二種明顯要比第一種方便,所以多數(shù)情況下會使用第二種方式。不過在某些情況下,實參無法提供足夠的類型信息給編譯器,那么就需要使用第一種形式。例如: 314java.lang.Integer java.lang.StringdemoGenMethods.showGenMsg(k,1); showGenMsg(str);public class demoGenMethods/定義泛型方法,有一個

32、形式參數(shù)用類型參數(shù) T 來定義 public static void showGenMsg(T ob, intn) T localOb = ob; /局部變量也可以用類型參數(shù) T 來定義 System.out.println(localOb.getClass().getName();public static void showGenMsg(Tob) System.out.println(ob.getClass().getNam e();public static void main(String args) String str = parameter; Integer k = new In

33、teger(123);/用兩種不同的方法調(diào)用泛型方法demoGenMethods.showGenMsg(k,1); showGenMsg(str);第 10 章 泛型 調(diào)用它的時候,根本就沒有實際參數(shù),所以編譯器無法知道 T 的實際類型,這種情況下,就必須使用第一種形式。 前面還提到,泛型方法也可以寫在泛型類中,比如: 這樣寫當然沒有錯誤,但多數(shù)程序員都會將這個泛型方法所需要的類型參數(shù) U 寫到類 的頭部,即讓泛型類帶兩個參數(shù): 這樣寫,類的結(jié)構(gòu)更為清晰。只有一種情況下必須在泛型類中再將方法聲明為泛型方法:方法本身是靜態(tài)的,那就無法像上面那樣更改了。 10.7泛 型 接 口除了泛型類和泛型方法

34、,還可以使用泛型接口。泛型接口的定義與泛型類非常相似,它的聲明形式如下: interface 接口名下面的例子創(chuàng)建了一個名為MinMax 的接口,用來返回某個對象集的最小值或最大值。 【例 10.6】 泛型接口示例。 /-文件名 MinMax.java,程序編號 10.11-這個接口沒有什么特別難懂的地方,類型參數(shù) T 是有界類型,它必須是 Comparable的子類。注意到 Comparable 本身也是一個泛型類,它是由系統(tǒng)定義在類庫中的,可以用來315interface MinMaxT extends Comparable T min(); T max();public class Ge

35、neric public void showGenMsg(U ob)System.out.println(ob.getClass().getName(); public class Generic public void showGenMsg(Uob) System.out.println(ob.getClass().getNam e(); public void doSomething() T ob; Java 開發(fā)技術(shù)大全比較兩個對象的大小。 接下來的事情是實現(xiàn)這個接口,這需要定義一個類來實現(xiàn)。筆者實現(xiàn)的版本如下:/-文件名 MyClass.java,程序編號 10.12-類的內(nèi)部并不難懂

36、,只要注意 MyClass 的聲明部分:看上去有點奇怪,它的類型參數(shù) T 必須和要實現(xiàn)的接口中的聲明完全一樣。反而是接口 MinMax 的類型參數(shù) T 最初是寫成有界形式的,現(xiàn)在已經(jīng)不再需要重寫一遍。如果重寫成下面這個樣子: 編譯將無法通過。 通常,如果一個類實現(xiàn)了一個泛型接口,則此類也是泛型類。否則,它無法接受傳遞給接口的類型參數(shù)。比如,下面這種聲明是錯誤的: 因為在類 MyClass 中需要使用類型參數(shù) T,而類的使用者無法把它的實際參數(shù)傳遞進來, 所以編譯器會報錯。不過,如果實現(xiàn)的是泛型接口的特定類型,比如: 這樣寫是正確的,現(xiàn)在這個類不再是泛型類。編譯器會在編譯此類時,將類型參數(shù) T

37、用 Integer 代替,而無需等到創(chuàng)建對象時再處理。 最后寫一個程序來測試 MyClass 的工作情況。 316class MyClass implements MinMaxclass MyClass implements MinMaxclassMyClassTextendsComparableimplementsMinMaxTextends Comparableclass MyClassT extends Comparable implements MinMaxclass MyClassT extends Comparable implements MinMax T vals;MyClas

38、s(T ob) vals = ob;public T min()T val = vals0;for(int i=1; ivals.length; +i) if (pareTo(val) 0)val = valsi; return val;public T max()T val = vals0;for(int i=1; i 0)val = valsi; return val;第 10 章 泛型 /-文件名 demoGenIF.java,程序編號 10.13-在使用類 MyClass 創(chuàng)建對象的方式上,和前面使用普通的泛型類沒有任何區(qū)別。程序 的輸出結(jié)果如下: 10.8泛型類的繼

39、承和普通類一樣,泛型類也是可以繼承的,任何一個泛型類都可以作為父類或子類。不過泛型類與非泛型類在繼承時的主要區(qū)別在于:泛型類的子類必須將泛型父類所需要的類型參數(shù),沿著繼承鏈向上傳遞。這與構(gòu)造方法參數(shù)必須沿著繼承鏈向上傳遞的方 式類似。 10.8.1以泛型類為父類當一個類的父類是泛型類時,這個子類必須要把類型參數(shù)傳遞給父類,所以這個子類也必定是泛型類。下面是一個簡單的例子。 【例 10.7】 繼承泛型類示例。 /-文件名 superGen.java,程序編號 10.14-317public class superGen /定義一個泛型類T ob;public superGen(T ob) thi

40、s.ob = ob;public superGen() ob =null;Max value in inums: 85 Min value in inums: 12 Max value in chs: z Min value in chs: bpublic class demoGenIFpublic static void main(String args) Integer inums =56,47,23,45,85,12,55;Character chs = x,w,z,y,b,o,p; MyClass iob = new MyClass(inums); MyClass cob = new

41、MyClass(chs); System.out.println(Max value in inums: +iob.max(); System.out.println(Min value in inums: +iob.min(); System.out.println(Max value in chs: +cob.max(); System.out.println(Min value in chs: +cob.min();Java 開發(fā)技術(shù)大全接下來定義它的一個子類: /-文件名 derivedGen.java,程序編號 10.15-注意 derivedGen 是如何聲明成 superGen

42、的子類的:public class derivedGen extends superGen這兩個類型參數(shù)必須用相同的標識符 T。這意味著傳遞給 derivedGen 的實際類型也會傳遞給 superGen。例如,下面的定義: derivedGen number = new derivedGen(100);將 Integer 作為類型參數(shù)傳遞給 derivedGen,再由它傳遞給 superGen,因此,后者的成員ob 也是 Integer 類型。 雖然 derivedGen 里面并沒有使用類型參數(shù) T,但由于它要傳遞類型參數(shù)給父類,所以它不能定義成非泛型類。當然,derivedGen 中也可以

43、使用 T,還可以增加自己需要的類型參數(shù)。下面這個程序展示了一個更為復雜的 derivedGen 類。 /-文件名 derivedGen.java,程序編號 10.16-使用泛型子類和使用其他的泛型類沒有區(qū)別,使用者根本無需知道它是否繼承了其他的類。下面是一個測試用的程序: /-文件名 demoHerit_1.java,程序編號 10.17-318public class demoHerit_1public static void main(String args)/創(chuàng)建子類的對象,它需要傳遞兩個參數(shù),Integer 類型給父類,自己使用 String 類型 public class deriv

44、edGen extends superGen U dob;public derivedGen(T ob1, U ob2) super(ob1);/傳遞參數(shù)給父類dob = ob2;/為自己的成員賦值 public U getDob() returndob;public class derivedGen extends superGen public derivedGen(T ob)super(ob);public T getOb() return ob;第 10 章 泛型 程序的輸出結(jié)果如下:10.8.2以非泛型類為父類前面介紹的泛型類是以泛型類作為父類,一個泛型類也可以以非泛型類為父類。此時

45、, 不需要傳遞類型參數(shù)給父類,所有的類型參數(shù)都是為自己準備的。下面是一個簡單的例子。 【例 10.8】 繼承非泛型類示例。 /-文件名 nonGen.java,程序編號 10.18-接下來定義一個泛型類作為它的子類: /-文件名 derivedNonGen.java,程序編號 10.19-這個泛型類仍然傳遞了一個普通參數(shù)給它的父類,所以它的構(gòu)造方法需要兩個參數(shù)。下面是用于測試的程序: /-文件名 demoHerit_2.java,程序編號 10.20-319public class demoHerit_2public static void main(String args)derivedNo

46、nGen oa =new derivedNonGen (Value is: , 100);System.out.print(oa.getOb(); System.out.println(oa.getNum();public class derivedNonGen extends nonGen T ob;public derivedNonGen(T ob, int n) super(n);this.ob = ob;public T getOb() return ob;publiValue is: 100derivedGen oa=new derivedGen (100,Value is: );S

47、ystem.out.print(oa.getDob(); System.out.println(oa.getOb();Java 開發(fā)技術(shù)大全程序的輸出結(jié)果如下:Value is: 10010.8.3運行時類型識別和其他的非泛型類一樣,泛型類也可以進行運行時類型識別的操作,既可以使用反射機制,也可以采用傳統(tǒng)的方法。比如,instanceof 操作符。 需要注意的是,由于在 JVM 中,泛型類的對象總是一個特定的類型,此時,它不再是泛型。所以,所有的類型查詢都只會產(chǎn)生原始類型,無論是 getClass()方法,還是 instanceof 操作符。 例如,對象 a 是 Generic類型(Gener

48、ic 是例 10.1 中定義的泛型類),那么 a instanceof Generic測試結(jié)果為真,下面的測試結(jié)果也為真:a instanceof Generic注意:尖括號中只能寫通配符“?”,而不能寫 Integer 之類確定的類型。實際上在測試時,“?”會被忽略。 同樣道理,getClass()返回的也是原始類型。若 b 是 Generic類型,下面的語句: a.getClass() = b.getClass()測試結(jié)果也為真。下面的程序演示了這些情況。 【例 10.9】 泛型類的類型識別示例 1。 /-文件名 demoRTTI_1.java,程序編號 10.21-程序的輸出結(jié)果如下:G

49、eneric object is instance of Generic320public class demoRTTI_1public static void main(String args) Generic iob = newGeneric(100); Generic sob = new Generic(Good); if (iob instanceof Generic)System.out.println(Generic object is instance of Generic); if (iob instanceof Generic)System.out.println(Generic object is instance of Generic);if (iob.getClass() = sob.getClass() System.out.println(Generic class equals Generic class);第 10 章 泛型 泛型類對象的類型識別還有另外一個隱含的問題,它會在繼承中顯示出來。例如,對 象 a 是某泛型子類的對象,當用 instanceof 來測試它是否為父類對象時,測試結(jié)果也為真。 下面的例子使用了例

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論