編程專題講座-java開發(fā)技術第10型_第1頁
編程專題講座-java開發(fā)技術第10型_第2頁
編程專題講座-java開發(fā)技術第10型_第3頁
編程專題講座-java開發(fā)技術第10型_第4頁
編程專題講座-java開發(fā)技術第10型_第5頁
已閱讀5頁,還剩20頁未讀 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第10章 泛型是JDK1.5中新加入的元素,它改變了API中的許多類和方法。使用泛型,的強大功能,從根本上改變了Java代碼的編寫方式。IntegerIntegermax(Integera,Integerb){returna>b?a:b;}IntegerDoubleFloat類型,那么就需要另外再寫max()方法。參數(shù)有多少種類型,就要寫多少個max()方法。但是無論怎么改變參數(shù)的類型,實際上max()方法體的代碼并不需要改變。如max()ab的數(shù)據(jù)類型,而等到調用的時候再來確定這兩個參數(shù)的數(shù)據(jù)類型,那么只需要編寫一個max()就可以了,這將大大在C++中,提供了函數(shù)模板和類模板來實現(xiàn)這能。而從JDK1.5開始,也提供了C++的模板很相似,但它們是采用完全不同的技在泛型出現(xiàn)之前,Java的程序員可以采用一種變通的辦法:將參數(shù)的類型均為ObjectObject類是所有類的父類,所以它可以指向任何類對象,但這樣做不能Object與實【10.1//--------------文件名Generic.java,程序10.1---------- publicclassTobobT,現(xiàn)在不能具體確定它的類型,需要到創(chuàng)建對象時才能確定Generic(To){ob=}TgetOb(){return}void}}//--------------文件名demoGeneric.java,程序10.2----------publicpublicclasspublicstaticvoidmain(String 一個Integer類型的Generic變Generic<Integer>//創(chuàng)建一個Integer類型的Generic對iobj=newintk=iobj.getOb(); 一個String類型的Generic變Generic<String>//創(chuàng)建一個Double類型的Generic對sobj=new Strings=sobj.getOb();}}TypeTypeofTis:java.lang.IntegerTypeofT publicclass 其中,TGeneric的實際類型的占位符。因此,在Generic中,每當需要類型參數(shù)時,就會用到T。注意,T是被括在“<>”中的。每個被的類型參數(shù),都要放在尖括號中。由于Generic使用了類型參T T只是一個占位符,所以ob的實際類型要由創(chuàng)建對象時的參數(shù)傳遞進來。比如,T的類型是StringobString類型。o){ob=}它的參oT。這o的實際類型,是由創(chuàng)Generic對象時傳遞ToobT類型,所以無論實際類型是什TTgetOb(){returnob;綜合上面的用法,可以看出,T是一個數(shù)據(jù)類型的說明,它可以用來說明任何實例方注意:類型參數(shù)T不能使用在靜態(tài)Generic 有對T的都會被替換為Integer。所以ob和o都是Integer類型,而且方法getOb()的返回類型也是Integer類型的。Java的編譯器并不會創(chuàng)建多個不同版本的Generic類。相反,編譯器會刪除所有iobjiobj=new所以用new返回的必須是Generic<Integer>類型。無論是省略Integer,還是將其改成iobjiobjnewGeneric<Double>(1.234錯Generic(TGeneric(TJava的自動裝箱機制(12.3節(jié)中介紹)。當然,創(chuàng)建對象也可iobjiobj=newGeneric(newintintk=注意,getObIntegerint變量時,系統(tǒng)會自動拆intintk=后面創(chuàng)建String版本的過程和前面的完全一樣,在此不再贅述。類型,而不能使用int或char之類的簡單類型。比如不能這樣寫:GenericGeneric<intobnewGenericint>(100);//錯C++模板的一個重要//--------------文件名twoGen.java,程序10.3----------publicclasstwoGen<T,V>{TVtwoGen(To1,Vo2){ob1=o1;ob2=}//顯示TV的類voidSystem.out.println("TypeofTis"+ob1.getClass().getName());System.out.println("TypeofVis"+ob2.getClass().getName());getOb1(){returnob1;getOb2(){eturn//--------------文件名simpGen.java,程序10.4----------publicpublicclasspublicstaticvoidargs[]){twoGen<Integer,String>tgObj; tgObj=newtwoGen<Integer,String>(100," intv=tgObj.getOb1();System.out.println("value:"+v);Stringstr=tgObj.getOb2();System.out.println("value:"+str);}TypeTypeofTisjava.lang.IntegerTypeofVisjava.lang.Stringvalue:100 與只有一個類型參數(shù)的泛型相比,本例并沒有什么難于理解的地方。Java并沒有規(guī)定 //--------------文件名Stats.java,程序10.5----------Stats<T>{T[]nums;Stats(Tobj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;++i)sum+=returnsum/其中,nums[i].doubleValue()Ingeger、Double等數(shù)據(jù)封裝類轉換成雙精度數(shù)后Number類的子類都有這個方法。但問題是,編譯器無法預先知道,程序員的意圖是只能使用Number類來創(chuàng)Stats對象,因此,編譯時會報告找不到doubleValue()classclassclassname<Textends【10.3//--------------文件名Stats.java,程序10.6----------////下面這個泛型的實際類型參數(shù)只能是Number或它的子classStats<TextendsNumber>{T[]nums;Stats(T[]obj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;sum+=nums[i].doubleValue(); returnsum/nums.length;}//--------------文件名demoBounds.java,程序10.7----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Integerinums[]=Stats<Integer> iobjnewStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobjnewStats<Double>(dnums);//如果像下面這樣創(chuàng)建String類型的對象將無法編譯通//Stringsnums[]=//Stats sobj=new//System.out.println("平均值}classStats<Textends 注意:這里使用的關鍵字仍然是extends而非implements。classStats<TextendsComparable& 注意:限界類型用“&”分隔,因為逗號用來分隔類型參數(shù)。在多個限界中StatsdoSomething()的方法,這個方法有一個形式參數(shù),也是Stats類型,如下所示:classclassvoiddoSomething(Statsob){}}IntegerIntegerinums[]=Stats<Integer> iobj=newStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobjnewStats<Double>(dnums);dobj.doSomething(iobj);//錯誤 voiddoSomething(Stats<T> voiddoSomething(Stats<U> 使用Java提供的通配符“?”,它的使用形式如下: voiddoSomething(Stats<?> 【10.4//--------------文件名Stats.java,程序10.8----------classclassStats<TextendsNumber>{T[]nums;Stats(T[]obj){nums=}average(){doublesum=0.0;for(inti=0;i<nums.length;++i)sum+=nums[i].doubleValue();returnsum/}voiddoSomething(Statsob){//這里使用了類型通配符}//--------------文件名demoWildcard.java,程序10.9----------publicclassdemoWildcard{publicpublicclassdemoWildcard{publicstaticvoidmain(Stringargs[]){Integerinums[]Stats<Integer> iobj=newStats<Integer>(inums);Doublednums[]={1.1,2.2,3.3,4.4,5.5};Stats<Double> dobj=newStats<Double>(dnums); } voiddoSomething(Stats<?>ob)//這里使用了類型通配 classStats<Textends Stats<?extendsInteger> Stats<?extendsString> IntegerNumberStringNumber的子類。通配符無法將上界改classStats<?extends 在C++中,除了可以創(chuàng)建模板類,還可以創(chuàng)建模板函數(shù)。在Java中也提供了類似的功能: 權限修飾符(包括private、public、protected)、static和final都必須寫在類 【10.5//--------------文件名demoGenMethods.java,程序10.10----------publicpublicclass//定義泛型方法,有一個形式參數(shù)用類型參數(shù)T來定publicstatic<T>voidshowGenMsg(Tob,n){TlocalObobT來}publicstatic<T>voidob){}publicstaticvoidmain(Stringargs[]){Stringstr="parameter";Integerk=newInteger(123);}型方法相互重載(參數(shù)的個數(shù)不同)T的使用和泛型類中的使用在第一種調用形式中,傳入了一個實際類型:<Integer>,它表明類型參數(shù)是 public<T>voiddoSomething(){public<T>voiddoSomething(){Tob;}publicclassGeneric<T>{publicpublicclassGeneric<T>{public<U>voidshowGenMsg(Uob){}}publicpublicclassU>{publicvoidshowGenMsg(U}interface接口名<類型參數(shù)表 //--------------文件名MinMax.java,程序10.11----------interfaceinterfaceMinMax<TextendsComparable<T>>{Tmin();Tmax();}T//--------------文件名MyClass.java,程序10.12----------classclassMyClass<TextendsComparable<T>>implementsMinMax<T>{T[]vals;MyClass(Tob){vals=}publicTTval=for(inti=1;i<vals.length;++i)if(vals[i].compareTo(val)<0)val=vals[i];returnval;}publicTTval=for(inti=1;i<vals.length;++i)if(vals[i].compareTo(val)>0)val=vals[i];returnval;}}classclassMyClass<TextendsComparable<T>>implements看上去有點奇怪,它的類型參數(shù)T必須和要實現(xiàn)的接口中的完全一樣。反而是接口MinMax的類型參數(shù)T最初是寫成有界形式的,現(xiàn)在已經(jīng)不再需要重寫一遍。如果重寫classclassMyClass<TextendsComparable<T>>implementsMinMax<TextendsclassclassMyClassimplementsclassclassMyClassimplements這樣寫是正確的,現(xiàn)在這個類不再是泛型類。編譯器會在編譯此類時,將類型參數(shù)T 代替,而無需等到創(chuàng)建對象時再處理//--------------文件名demoGenIF.java,程序10.13----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Integerinums[]=Characterchs[]={'x','w','z','y','b','o','p'};MyClass<Integer>iob=newMyClass<Integer>(inums);MyClass<Character>cob=newMyClass<Character>(chs);System.out.println("Maxvalueininums:"+iob.max());System.out.println("Minvalueininums:"+iob.min());System.out.println("Maxvalueinchs:"+cob.max());System.out.println("Minvalueinchs:"+cob.min());}MaxMaxvalueininums:85Minvalueininums:12Maxvalueinchs:zMinvalueinchs:和普通類一樣,泛型類也是可以繼承的,任何一個泛型類都可以作為父類或子類。不過泛型類與非泛型類在繼承時的主要區(qū)別在于:泛型類的子類必須將泛型父類所需要的類型參數(shù),沿著繼承鏈向上傳遞。這與構造方法參數(shù)必須沿著繼承鏈向上傳遞的方式類似。以泛型類為父【10.7//--------------文件名superGen.java,程序10.14----------publicpublicclasssuperGen<T定義一個泛型類Tob;publicsuperGen(Tob){this.ob=ob;}superGen(){ob=publicTpublicTgetOb(){return}//--------------文件名derivedGen.java,程序10.15----------publicclassderivedGen<T>extendssuperGen<T>{publicclassderivedGen<T>extendssuperGen<T>{publicderivedGen(Tob){}}publicclassderivedGen<T>extends 這兩個類型參數(shù)必須用相同的標識符T。這意味著傳遞給derivedGen的實際類型也會傳遞給superGen。例如,下面的定義:derivedGen<Integer>number=new IntegerderivedGensuperGen,因此,后者的成員ob也是Integer類型。雖然derivedGen里面并沒有使用類型參數(shù)T,但由于它要傳遞類型參數(shù)給父類,所以它不能定義成非泛型類。當然,derivedGenT,還可以增加自己需要的類型參數(shù)。下面這個程序展示了一個更為復雜的derivedGen類。//--------------文件名derivedGen.java,程序10.16----------publicpublicclassderivedGen<T,U>extendssuperGen<T>{Udob;publicderivedGen(Tob1,Uob2){super(ob1); 數(shù)給父類dob=ob2; }publicUgetDob(){return//--------------文件名demoHerit_1.java,程序10.17----------publicpublicclasspublicstaticvoidmain(String//創(chuàng)建子類的對象,它需要傳遞兩個參數(shù),Integer類型給父類,自己使用String類derivedGen<Integer,String>derivedGen<Integer,String>oa=newderivedGen<Integer,String>(100,"Valueis:");}}ValueValueis:以非泛型類為父【10.8//--------------文件名nonGen.java,程序10.18----------}//--------------文件名derivedNonGen.java,程序10.19----------publicpublicclassderivedNonGen<T>extendsnonGen{Tob;publicderivedNonGen(Tob,intn){super(n);this.ob=}publicTgetOb(){return}//--------------文件名demoHerit_2.java,程序10.20----------publicpublicclasspublicstaticvoidmain(StringderivedNonGen<String>oa=newderivedNonGen<String>("Valueis:",}}Valueis: 運行時類型識機制,也可以采用傳統(tǒng)的方法。比如,instanceof操作符。JVM中,泛型類的對象總是一個特定的類型,此時,它不再ainstanceof antnefGc 注意:Integer之類確定的類型。實際上在測同樣道理,getClass()返回的也是原始類型。若b是Generic<String>類型,下面a.getClass()== //--------------文件名demoRTTI_1.java,程序10.21----------publicpublicclasspublicstaticvoidmain(Stringargs[]){Generic<Integer>iob=newGeneric<Integer>(100);Generic<String>sob=newGeneric<String>("Good");if(iobinstanceofSystem.out.println("Generic<Integer>objectisinstanceofGeneric");if(iobinstanceofGeneric<?>)System.out.println("Generic<Integer>objectisinstanceofif(iob.getClass()==sob.getClass())System.out.println("Generic<Integer>classequalsGeneric<String>}Generic<Integer>objectisinstanceof Generic<Integer>objectisinstanceofGeneric<?>Generic<Integer>Generic<Integer>objectisinstanceofGeneric<?>Generic<Integer>classequalsGeneric<String>class//--------------文件名demoRTTI_2.java,程序10.22----------publicpublicclasspublicstaticvoidmain(StringsuperGen<Integer>oa=newsuperGen<Integer>(100);derivedGen<Integer,String>ob=newderivedGen<Integer,if(oainstanceofSystem.out.println("superGenobjectisinstanceofderivedGen");if(obinstanceofsuperGen)System.out.println("derivedGenobjectisinstanceofsuperGen");if(oa.getClass()==ob.getClass())System.out.println("superGenclassequalsderivedGen}}derivedGenobjectisinstanceof 強制類型 個類:superGen和derivedGen?!?0.11//--------------文件名demoForceChange.java,程序10.23----------publicpublicclasspublicstaticvoidmain(StringsuperGen<Integer>oa=newsuperGen<Integer>(100);derivedGen<Integer,String>ob=newderivedGen<Integer,String>if((superGen<Integer>)obinstanceofSystem.out.println("derivedGenSystem.out.println("derivedGenobjectischangedtoif((derivedGen<Integer,String>)oainstanceofderivedGen)System.out.println("superGenobjectischangedtoderivedGen");}}derivedGenderivedGenobjectischangedtoExceptioninthread"main"java.lang.ClassCastException:at提示:建議讀者如果不是十分必要,不要做強制類型轉換的操作么對應的泛型是否也會具有相同的繼承關系呢?比如,Integer是Number的子類,那么Generic<Integer>Generic<Number>的子類呢?答案是:否。比如,下面的代碼將不Generic<Number>Generic<Number>oa=newoaGeneric<Integer>的父類,所以這條語句無法編譯通過。事實上,10.1Generic類之間沒有繼承 Jvacas文件的細節(jié)。但在使用泛型時,對此過程進行一般的了解是必要的,因為只有了解這一細節(jié),程序員才能理解JavaJDK1.5以前的版本中是沒有泛型的,為了保證對以前版本的兼容,Java采用C++的模板完全不同的方式來處理泛型(盡管它們二者的使用看上去很相似),Java【10.12//--------------文件名Gen.java,程序10.24----------////默認情況下,T是由Object限publicclassTob;Gen(Tob){this.ob=getOb(){returnob;}javap CompiledCompiledfrom"Gen.java"publicclassGenjava.lang.Object{java.lang.Objectob; 面將T稱為“占位符”的原因。【10.13//--------------文件名GenStr.java,程序10.25----------//T//T是由String限publicclassGenStr<TextendsTob;GenStr(Tob){this.ob=getOb(){returnob;}CompiledCompiledfrom"GenStr.java"publicclassGenStrjava.lang.Object{java.lang.Stringob;java.lang.StringgetOb();}Gen<Integer>Gen<Integer>oa=newGen<Integer>(100);Gen<Integer>ob=oa.getOb();Gen<Integer>ob= 具體指定的參數(shù)類型。這一點在10.8.3小節(jié)中已經(jīng)詳細介紹過了。也被稱為。主要發(fā)生在下述三種情況。靜態(tài)成員共享問//--------------文件名foo.java,程序10

溫馨提示

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

評論

0/150

提交評論