Java泛型技术之发展与JDK14上的实现_第1页
Java泛型技术之发展与JDK14上的实现_第2页
Java泛型技术之发展与JDK14上的实现_第3页
Java泛型技术之发展与JDK14上的实现_第4页
Java泛型技术之发展与JDK14上的实现_第5页
已阅读5页,还剩69页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1綱要GenericsHistoryandOverviewJavaCollectionClassesGenericsinJava-programmingGenericsinJava-underlyingtech.GenericsinC++-STL2JavaCollectionClasses1.HistoricalCollectionClasses(~Java1.1)Arrays,Vector,Stack,Hashtable,Properties,BitSet2.CollectionsFramework(J2SE,Java1.2~)Sets,Lists,Maps3.AlternativeCollectionLibrariesJGLfromObjectSpaceutil.concurrent,Colt4.GenericTypesGenericJava(GJ),PolyJ,JSR14(JDK1.4)Ref.《JavaCollections》p13JavaCollectionFramework面對諸如C++StandardTemplateLibrary(STL)之類的(資料結構和演算法)技術,Sun提出一個簡略方案,就是JavaCollectionsFramework。CollectionsFramework由三部分組成:1.Interfaces(abstractclasstypesthatframeworksupport,Collection,List,Set,SortedSet,Map,SortedMap)2.Implementations(HashSet,HashMap,WeakHeahMap,ArrayList,TreeSet,TreeMap,LinkedList,allareserializableandcloneable)3.Algorithms(inclassArrays

andCollections,allofstaticmethods)Ref.《JavaCollections》p1174EnumerationInterface

inhistoricalclassesEnumerationenum

=…;while(enum.hasMoreElements()){Objecto=enum.nextElement();processObject(o);}for(Enumerationenum=…;enum.hasMoreElements();){Objecto=enum.nextElement();processObject(o);}提供一個走訪群集內所有元素的標準方式Ref.《JavaCollections》p70每一個舊式的collectionclasses都提供有一個method(enumeration()或elements()),用來給你一個列舉器。使用enumeration時絕不能修改底部群集。5voidCDocument::UpdateAllViews(...)//巡訪所有的views{

POSITIONpos=m_viewList.GetHeadPosition();while(pos!=NULL){CView*pView=(CView*)m_viewList.GetNext(pos);if(pView!=pSender)//注意,我們不讓自己通知自己

pView->OnUpdate(pSender,lHint,pHint);}}EnumerationInterface

inMFC提供一個走訪群集內所有元素的標準方式Ref.MFCsource6IteratorInterface

inCollectionsFramework《Interface》Iterator《Interface》ListIteratorCollectionc=...;Iterator

i=c.iterator();while(i.hasNext()){process(i.next());}提供一個走訪群集內所有元素的標準方式Ref.《JavaCollections》p1297IteratorInterface

inC++STLlist<int>myList=...;list<int>::iteratori=myList.begin();while(i!=myList.end()){process(*(i++));}8PredicateInterface(use)

FilterIteratorinJava帶有條件(有過濾能力)的迭代器publicclassPredTest{staticPredicate

pred=newPredicate(){publicboolean

predicate(Objecto){returno.toString().startsWith("Hi");}};publicstaticvoidmain(Stringargs[]){Listlist=Arrays.asList(args);Iteratori1=list.iterator();Iteratori=newPredicateIterator(i1,pred);while(i.hasNext()){System.out.println(i.next());}}}先產生一個一般迭代器,再據此產生一個「條件迭代器」定義自己的條件式Ref.《JavaCollections》p1329classPredicateIteratorimplementsIterator{publicPredicateIterator(Iteratoriter,Predicatepred){//...}publicvoidremove(){//...}publicbooleanhasNext(){//...}publicObjectnext(){//...}}interfacePredicate{booleanpredicate(Objectelement);}條件迭代器介面:需實作出Iteratorinterface,亦即需有remove(),hasNext(),next()三個methods。其建構式接受一個一般迭代器和一個條件式。條件式的介面如上,需有一個測試真假的函式,並傳回真假值。條件式介面:需有一個測試條件真假結果的函式predicate(),並傳回測試結果(真假值)PredicateInterface(implement)

FilterIteratorinJavaRef.《JavaCollections》p13010count_if(c.begin(),c.end(),

not1(bind2nd(less<int>(),40)));PredicateInterface(use)

functors&functionadaptersinC++STL帶有條件(有過濾能力)的演算法。條件可層疊「配接」11AlgorithmsinCollectionFramework

publicstaticvoidsort(Listlist);publicstaticvoidsort(Listlist,Comparatorcomp);publicstaticintbinarySearch(Listlist,Objectkey);publicstaticintbinarySearch(Listlist,Objectkey,Comparatorcomp);publicstaticObjectmin(Collectioncol);publicstaticObjectmin(Collectioncol,Comparatorcomp);publicstaticObjectmax(Collectioncol);publicstaticObjectmax(Collectioncol,Comparatorcomp);publicstaticvoidshuffle(Listlist);publicstaticvoidshuffle(Listlist,Randomrnd);publicstaticvoidfill(Listlist,Objectelement);publicstaticvoidcopy(Listdest,Listsrc);inclassCollectionsRef.《JavaCollections》p22712JGLfromObjectSpaceInc.

13JGLfromObjectSpaceInc.

14GenericProgramming

inJavaJava為保持其語言的簡單性,強迫你(程式員)動手做一些事情:你必須記住你所擁有的是個listofbytes(或strings或lists);當你從中萃取出一個元素時,更進一步處理之前必須先將它轉型,從classObject

轉為classByte(或String

或List)。Java2的collectionsframework就是以此方式對待各種容器類別。如果以泛型(generictypes)來擴充Java語言,就有可能以一種更直接的方法來表現lists的相關資訊。於是編譯器可以追蹤記錄你是否擁有一個listofbytes(或strings或lists),而你也就不再需要將型別轉回classByte(或String

或List<String>)。某種情況下這很類似Ada語言的generics或C++語言的templates。Ref."GJ:AGenericJava"15GenericProgramming

inJava在Java語言中,List

是異質性的(heterogenous)--它們可以擁有任何型別的元素,沒有任何辦法可以強迫它們擁有相同型別。然而在JavawithGenerics

中,List卻是同質性的(homogenous)—

它們必須擁有相同型別的元素,編譯器會厲行這一點;此時如果你真的需要一個List

擁有不同型別的元素,應該使用List<Object>。JavawithGenerics

以角括號標示型別參數,原因是C++使用者對它們比較熟悉,而且其他型式的括號可能會帶來混淆。Ref."GJ:AGenericJava"16JavawithGenerics

featuresJavawithGenerics(GJ,JDK1.4-with-Generics)的幾個關鍵特性包括:相容於Java語言。GJ是Java的超集。每一個Java程式在JavawithGenerics中都仍然合法而且有著與過去相同的意義。相容於Java虛擬機器(JVM)。JavawithGenerics被編譯為JVM碼。JVM不需任何改變。因此Java所能執行之處,JavawithGenerics都能執行,包括在你的瀏覽器上。相容於既有程式庫。既有的程式庫都能夠和JavawithGenerics共同運作,即使是編譯後的.classbinary型式。有時候我們也可以將一個舊程式庫翻新,加上新式型別,而不需更動其源碼。例如Javacollectionsframework就可以被這樣翻新,加上泛型特性。高效(efficiency)。與泛型(generictypes)相關的資訊,只有在編譯期(而非執行期)才被維護著。這意味編譯後的JavawithGenericscode幾乎完全和相同目的、相同效率的Javacode一致。Ref."GJ:AGenericJava"17JavawithGenerics

編譯器的工作是把JavawithGenericscode翻譯回一般的Javacode。這個翻譯程序僅僅只是消除型別參數(typeparameters)並加上轉型動作。例如它把JavawithGenerics

classList<Byte>

譯回JavaclassList,並加上轉型,在必要地點將Object

轉為Byte。獲得的結果就像在不支援泛型的情況下你所寫的Javacode一樣。這就是為什麼我們能夠輕易為JavawithGenerics和既有的Java程式庫建立介面的原因,這也是為什麼JavawithGenerics

能夠和Java擁有相同效率的原因。JavawithGenerics

保證任何一個被編譯器加入的轉型動作都不會導致錯誤。在這些保證之下,由於JavawithGenerics

將程式碼翻譯為JVMbytecodes,所以Java平台原本擁有的安全性(safety)和防護性(security)也都獲得了保留。JavawithGenerics

underlyingtech.Ref."GJ:AGenericJava"18為了將JavawithGenerics

翻譯為Java語言,必須為每一個型別做一種特殊的擦拭(erasure)動作。一個參數化型別,經過擦拭後應該除去參數(於是List<T>

被擦拭為List),一個未被參數化的型別,經過擦拭後應該獲得型別本身(於是Byte

被擦拭為Byte),而一個型別參數經過擦拭後,結果為Object(於是T

被擦拭後變成Object)(註:稍後另有擴充定義)。如果某個methodcall

的傳回型別是個型別參數,編譯器會為它安插適當的轉型動作。因此,一個「根據GJ代碼完成的新程式」,可以和一個「根據Java代碼完成的舊程式庫」放在一起編譯。JavawithGenerics

underlyingtech.Ref."GJ:AGenericJava"19JavawithGenerics

underlyingtech.JavawithGenericscode被編譯為Javacode之後,其結果就像你在無泛型性質的情況下所寫的程式。JavawithGenerics

編譯器將額外的型別標記(type-signature)儲存於JVMclassfiles。.class檔案格式允許如此擴充,並於執行期被JVM忽略。所謂翻新就是取出原有的Javaclassfile,檢查其型別標記是否如同「JavawithGenerics

型別標記被擦拭後」的結果,然後產生一個帶有JavawithGenerics

標記的嶄新classfile。Java2的整個collectionclasslibrary已經以此方式翻新。程式庫中的每一個publicinterface,class,和method都有一個適當對應的JavawithGenerics

型別。由於翻新後的classfiles與原先不同之處只在於新增加的那些JavawithGenerics

型別標記(它會於執行時期被JVM忽略),所以你可以將其結果在一個Java2相容瀏覽器中執行,不需重新載入collectionclasslibrary。Ref."GJ:AGenericJava"20JavawithGenerics

underlyingtech.C++expansionvs.JavaerasureC++templates以膨脹法(expansion)實作出來,編譯器針對被運用的每一個型別,為泛型代碼產生一份對應副本。這往往導致程式碼的體積膨脹。由於template可能被定義於一個檔案之中而被另一個檔案使用,膨脹法所引起的錯誤往往無法被偵測出來,直到聯結期才會記錄,而且往往難以回溯。ThePracticeofProgramming(Addison-Wesley)曾記錄過一個C++小程式的templates產出一個名稱長達1594字元的變數

JavawithGenerics以拭去法(erasure)實作出來,沒有膨脹問題。型別變數必須滿足的所有條件,都已經在其bounds中清楚指定了,因此所有錯誤都會在編譯期就被偵測出來,不會等到聯結期。Java屬於所謂動態聯結,聯結期和執行期一致。型別參數必須總是一個指引型別(例如Byte)而不是一個基本型別(例如byte)。Ref."GJ:AGenericJava"21GJ

:AGenericJavaLanguageExtension

Ref."GJ:AGenericJava"22GJ(GenericJava)

installation從/~wadler/gj/下載gjdist1.2.zip解壓縮,預設置於C:\GJ\...SRC<DIR>04-12-02CLASSES<DIR>04-12-02DOC<DIR>04-12-02GJCBAT5108-05-99VERSIONTXT1,15208-05-99GJCRBAT13404-12-02java-ms12mgjc.Main-bootclasspath

c:\gj\classes\;c:\jdk1.3\jre\lib\rt.jar;c:\jdk1.3\jre\lib\i18n.jar%1%2%3%4%5%6%7%8%9\GJ\gjcr.bat:(按文件上的說明,自行完成此一批次檔)內有java.util.Collections,gjc.MainSRC\COM\SUN\JAVA\UTIL\COLLECTIONS

內有LinkedList.java等,都是重寫檔。23GJ(GenericJava)

pathsetting(forcoreclasses)Java屬於動態連結,不論JDK內附工具或一般Java程式,最終都會喚起JRE,其內都是類別庫。有些類別庫是所謂coreclasses,為求安全JRE載入classes之前會先查看coreclasses中是否有同名者(package+className),如有就優先載入。例如JDK內附的java.util.Collection

未支援泛型,如果你有一個支援泛型的版本,並將它放在

-classpath

內,系統一定會優先載入coreclasses。為此我們必須運用-bootclasspath改變JRE載入coreclasses的順序,讓c:\gjc\classes\下的java.util.Collection先被載入。gjc.Main

是GJ編譯器(技術上比較像前處理器,因為它負責「擦拭」泛型),那些-bootclasspath

選項都是gjc.Main所用,不是java.exe所用。-ms12n就是一般Java編譯器的-Xms12n,只要鍵入java-X就可以看到這些選項的說明,它是為了讓JVM預設配置更多heap,因為泛型編譯很耗費記憶體。-J-Xbootclasspath/p都是JVM內部所用參數,一般並不公開,其優先權比

-bootclasspath還高罷了。這些都是為了載入正確的coreclasses而進行的路徑調整。24GJ(GenericJava)

environmentsetting@echooffremJDK1.3(36.bat)withGenericJava(GJ)remappendingC:\GJtoPATH(asbelow)isjustforgjc(r).batsetPATH=C:\jdk1.3\bin;C:\WINDOWS;C:\WINDOWS\COMMAND;C:\GJsetclasspath=.;d:\tij2\prog;d:\jdk1.3\lib\tools.jar;C:\GJ\classesclssetforgjcr(.bat)forgjc.Main25GJ(GenericJava)

environment26JDK1.427從http://java.下載JDK1.4並安裝預設置於c:\J2SDK_Forte\jdk1.4.0BIN<DIR>04-13-023:46binJRE<DIR>04-13-023:46jreLIB<DIR>04-13-023:47libREADMETXT8,27702-07-0212:52README.txtLICENSE13,85302-07-0212:52LICENSECOPYRI~14,51602-07-0212:52COPYRIGHTREADME~1HTM15,29002-07-0212:52readme.htmlINCLUDE<DIR>04-13-023:48includeDEMO<DIR>04-13-023:48demoSRCZIP10,377,84802-07-0212:52src.zipJDK1.4

installation28JSR-00001429JAVACJAR448,17503-13-0213:05javac.jarCHANGES32003-13-0212:54CHANGESCOPYRI~11,20103-13-0212:54COPYRIGHTLICENSE10,52203-13-0212:59LICENSEREADME2,37403-13-0212:54READMECOLLECTJAR44,39203-13-0213:04collect.jarJAVAC<DIR>04-13-023:06javacEXAMPLES<DIR>04-13-023:06examplesSCRIPTS<DIR>04-13-023:06scripts從/jsr/detail/14.jsp下載adding_generics-1_2-ea.zip解壓縮,預設置於c:\jsr14_adding_generics-1_2-ea源碼JSR-000014

installationjavac\com\sun\tools\javac\v8\util\Set.java,不是個retrofittingfile.javac\com\sun\tools\javac\v8\util\List.java,不是個retrofittingfile.javac\com\sun\tools\javac\v8\tree\Tree.java,不是個retrofittingfile.Q:沒有retrofittingfiles,又沒有完整的rewrittingfiles,那麼JSR14究竟如何讓Collections獲得泛型支援呢?NOTE:javac\com\sun\tools\javac\v8\Retro.java,是retrofitter源碼(詳列於本投影檔最後)30javag.bat@echooff:J2SE14ifnotexist%J2SE14%\bin\javac.exegotoBADJ2SE14ifnotexist%J2SE14%\jre\lib\rt.jargotoBADJ2SE14gotoJSR14DISTR:BADJ2SE14echo%J2SE14%doesnotpointtoaworkingJ2SE1.4installation.gotoend:JSR14DISTRifnotexist%JSR14DISTR%\javac.jargotoBADJSR14DISTRifnotexist%JSR14DISTR%\collect.jargotoBADJSR14DISTRgotoargs:BADJSR14DISTRecho%JSR14DISTR%doesnotpointtoaworkingJSR14installation.gotoend:argsifnot"%1"==""gotocompile%J2SE14%\bin\javac-J-Xbootclasspath/p:%JSR14DISTR%\javac.jargotoend:compile%J2SE14%\bin\javac-J-Xbootclasspath/p:%JSR14DISTR%\javac.jar-bootclasspath%JSR14DISTR%\collect.jar;%J2SE14%\jre\lib\rt.jar

-gj-warnunchecked%1%2%3%4%5%6%7%8%9:end(jjhou

新添)31JDK1.4withGenerics

environmentsetting@echooffremjdk1.4(noteJSR14DISTRandJ2SE14)setPATH=c:\J2SDK_Forte\jdk1.4.0\bin;C:\WINDOWS;C:\WINDOWS\COMMANDsetclasspath=.;d:\tij2\prog;c:\J2SDK_Forte\jdk1.4.0\lib\tools.jarsetJSR14DISTR=c:\jsr14_adding_generics-1_2-easetJ2SE14=c:\J2SDK_Forte\jdk1.4.0clssetC:\>javac

等同於C:\>java-classpathc:\jdk1.3\lib\tools.jarcom.sun.tools.javac.Main提示:32JDK1.4withGenerics

environment33JDK1.4withGenerics

sampleTest.javaEmployee.java//forGJ://build:gjcr.batTest.java[o]//options:-nowarnor-unchecked//note:GJCR不接受PE2'sEOF////forJDK1.4withJSR14://build:javag.batTest.java//options:-gj-warnunchecked(已內嵌於javag.bat中)//note:JDK14接受PE2'sEOF//note:無法接受boundedtypeparameter.Ref.Test.java34JDK1.4withGenerics

sample.1LinkedList<Integer>il=newLinkedList<Integer>();il.add(newInteger(0));il.add(newInteger(1));il.add(newInteger(5));il.add(newInteger(2));Integermaxi=Collections.max(il);//AlgorithmSystem.out.println(maxi);//5Collections.sort(il);//AlgorithmSystem.out.println(il);//[0,1,2,5]Ref.Test.java35JDK1.4withGenerics

sample.2LinkedList<String>sl=newLinkedList<String>();sl.add("zero");sl.add("one");sl.add("two");sl.add("five");System.out.println(sl);//[zero,one,two,five]Stringmaxs=Collections.max(sl);//AlgorithmSystem.out.println(maxs);//zeroCollections.sort(sl);//AlgorithmSystem.out.println(sl);//[five,one,two,zero]Ref.Test.java36JDK1.4withGenerics

sample.3LinkedList<LinkedList<String>>sll

=newLinkedList<LinkedList<String>>();sll.add(sl);Stringtemps2=sll.iterator().next().iterator().next();System.out.println(temps2);//fiveSystem.out.println(sll);//[[five,one,two,zero]]Ref.Test.java37JDK1.4withGenerics

sample.4ArrayList<Double>da=newArrayList<Double>();da.add(newDouble(3.3));da.add(newDouble(1.1));da.add(newDouble(5.5));da.add(newDouble(2.2));System.out.println(da);//[3.3,1.1,5.5,2.2]Collections.sort(da);//CollectionFramework'sAlgorithmSystem.out.println(da);//[1.1,2.2,3.3,5.5]Ref.Test.java38Vector<Character>cv=newVector<Character>();cv.add(newCharacter('j'));cv.add(newCharacter('j'));cv.add(newCharacter('H'));cv.add(newCharacter('o'));cv.add(newCharacter('u'));System.out.println(cv);//[j,j,H,o,u]Collections.sort(cv);//CollectionFramework'sAlgorithmSystem.out.println(cv);//[H,j,j,o,u]JDK1.4withGenerics

sample.5Ref.Test.java39JDK1.4withGenerics

sample.6HashSet<String>shs=newHashSet<String>();shs.add(newString("jjhou"));shs.add(newString("jason"));shs.add(newString("jamie"));shs.add(newString("jeremy"));shs.add(newString("jiangtao"));shs.add(newString("jou"));System.out.println(shs);//[jjhou,jason,jeremy,jiangtao,jamie,jou]Ref.Test.java40JDK1.4withGenerics

sample.7TreeSet<Long>lts=newTreeSet<Long>();lts.add(newLong(5));lts.add(newLong(2));lts.add(newLong(7));lts.add(newLong(4));System.out.println(lts);//[2,4,5,7]Ref.Test.java41JDK1.4withGenerics

sample.8HashMap<Integer,String>ishm=newHashMap<Integer,String>();ishm.put(newInteger(3),newString("jjhou"));ishm.put(newInteger(1),newString("jason"));ishm.put(newInteger(9),newString("jamie"));ishm.put(newInteger(7),newString("jiang"));System.out.println(ishm);//{9=jamie,7=jiang,3=jjhou,1=jason}Ref.Test.java42JDK1.4withGenerics

sample.9TreeMap<Integer,String>istm=newTreeMap<Integer,String>();istm.put(newInteger(3),newString("jjhou"));istm.put(newInteger(1),newString("jason"));istm.put(newInteger(9),newString("jamie"));istm.put(newInteger(7),newString("jiang"));System.out.println(istm);//{1=jason,3=jjhou,7=jiang,9=jamie}Ref.Test.java43JDK1.4withGenerics

sample.10,case1(genericsforuser-definedclasses)Employeeempv[]={newEmployee("Finance","Degree,Debbie"),newEmployee("Engineering","Measure,Mary"),};Set<Employee>emps=newTreeSet<Employee>(Arrays.asList(empv));System.out.println(emps);EmployeemaxEmp=Collections.max(emps);publicclassEmployeeimplementsComparable<Employee>{publicintcompareTo(Employeeemp){...}User-definedclassRef.Test.java,Ref.Employee.java44JDK1.4withGenerics

sample.10,case2(non-genericsforuser-definedclasses)Employeeempv[]={newEmployee("Finance","Degree,Debbie"),newEmployee("Engineering","Measure,Mary"),};Setemps=newTreeSet(Arrays.asList(empv));System.out.println(emps);EmployeemaxEmp=(Employee)Collections.max(emps);publicclassEmployeeimplementsComparable{publicintcompareTo(Objectobj){

Employeeemp=(Employee)obj;...}User-definedclass45JDK1.4withGenerics

sample.11,genericmethod&boundedtypeparameterLinkedList<Employee>empl=newLinkedList<Employee>(Arrays.asList(empv));System.out.println(Test.gm(empl));//genericmethod&boundedtypeparameter.//<TimplementsComparable<T>>T

gm(List<T>list)//methodaboveERRORinJDK14,SUCCESSinGJ.publicstatic<T>T

gm(List<T>list){Ttemp=list.iterator().next();//getthefirstonereturntemp;//andjustreturn.}method如果擁有自己的型別參數,我們稱為一個“genericmethod”,型別參數如果必須實作出某個已知介面(或必須是某已知class的subclass),我們稱之為“bounded”(受限的)。擦拭(erasure)的定義有必要擴充為:一個型別變數經過擦拭,相當於其bound

的擦拭結果(這麼一來gm()中的T

便被擦拭為Comparable)。Ref."GJ:AGenericJava"Ref.Test.java46JDK1.4withGenerics

sample.11,dumpbydumpclassThisclasshas1fields.F0:staticjava.util.LinkedList

emplSignature<2bytes>read():Readfieldinfo...M0:publicvoid<init>();M1:publicstaticvoidmain(java.lang.Stringa[]);M2:publicstaticjava.lang.Object

gm(java.util.Lista);M3:staticvoid<clinit>();...Thisclasshas1fields.F0:staticjava.util.LinkedList

emplSignature<2bytes>read():Readfieldinfo...M0:publicvoid<init>();M1:publicstaticvoidmain(java.lang.Stringa[]);M2:publicstaticjava.lang.Comparable

gm(java.util.Lista);M3:staticvoid<clinit>();...CompiledbyJDK1.4withGenericsCompiledbyGJ47JDK1.4withGenerics

sample.11,dumpbydumpclassI0:Class:java/lang/ComparableM0:publicvoid<init>(java.lang.Stringa,java.lang.Stringb);M1:publicintcompareTo(Employeea);M2:publicintcompareTo(java.lang.Objecta);...publicsynchronizedclassEmployeeextendsjava.lang.Object

implementsjava/lang/Comparable{...CompiledbyJDK1.4withGenericsCompiledbyGJBridge48JDK1.4withGenerics

sample.11,genericmethod&boundedtypeparameterLinkedList<Employee>empl=newLinkedList<Employee>(Arrays.asList(empv));System.out.println(Test.gm(empl));//genericmethod&boundedtypeparameter.publicstatic<TimplementsComparable<T>>T

gm(List<T>list){...}gm()接受一個list,其內的元素型別都是T,傳回一個元素,型別亦為T。最前面的角括號內宣告了型別參數T,並指出這個method可被任意型別T具現化(instantiated)—

只要T實作出Comparable<T>介面。面對呼叫動作,編譯器自動推導出gm()標記式(signature)中的型別參數T必須被具現化為Employee,並檢查classEmployee確實實作了boundComparable<Employee>。一般而言導入bound

的方式是,在型別參數之後寫上"implements"再加一個interface名稱,或是在型別參數之後寫上"extends"再加一個class名稱。不論是在classhead或是genericmethod標記式中,凡型別參數可以出現之處,bounds都可以出現。boundinginterface或boundingclass本身可能又被參數化,甚至可能形成遞迴(recursive),例如上述例子中的boundComparable<T>就內含了bounded型別參數T。Ref."GJ:AGenericJava"49JavawithGenerics

erasurerulesRef."GJ:AGenericJava"一個參數化型別經過擦拭後應該去除參數(於是List<T>

被擦拭成為List)一個未被參數化的型別經過擦拭後應該獲得型別本身(於是Byte被擦拭成為Byte)一個型別參數經過擦拭後的結果為Object(於是T

被擦拭後變成Object)一個型別變數經過擦拭後的結果為其bound的擦拭結果(於是gm()中的T便被擦拭為Comparable)如果某個methodcall的回傳型別是個型別參數,編譯器會為它安插適當的轉型(於是Empolyeetemp=Test3.gm(empl)

會被編譯器改為Empolyeetemp=(Employee)Test3.gm(empl),不過這個動作在dumpclass的分析報告中顯現不出來)50JavawithGenerics

retrofittingRef."GJ:AGenericJava"JQueue<T>NQueueretrofit.class(genericform)compiledbyJDK1.4+JSR14obsolete.class(non-genericform)compiledbyJDK1.3,andnosourceexistJQueue<Employee>xxxJQueuexxxNQueuexxxNQueue<Employee>xxxApp.(compiledbyJDK1.4+JSR14)CH[o],R[o]CH[o],R[o]CH[o],R[o]CH[o],R[x](warning)CH:compilecheckR:running同一類別之非泛型和泛型兩種型式可以使用相同名稱,「檔名相同」的問題只要透過package即可解決。圖中之JQueue<>和NQueue其實可使用相同名稱。Test2.classJQueue.classNQueue.class翻新檔(retrofittingfiles)的目的是為舊式.class提供額外的型別資訊),供編譯器於日後編譯泛型應用程式時比對之用(才能檢查出語法錯誤)。51JavawithGenerics

retrofittingRef.GJ-Tutorial.pdf-d<directory>Specifywheretoplacegeneratedclassfiles-gjAcceptgenericsinthelanguage(thedefault)-retrofit<pathname>Retrofitexistingclassfileswithgenerictypes52JDK1.4withGenerics

sample.12,serialization(lightweightpersistence)writeObjectOutputStreamout=newObjectOutputStream(newFileOutputStream("collect.out"));out.writeObject(il);out.writeObject(sl);out.writeObject(sll);out.writeObject(da);out.writeObject(cv);out.writeObject(shs);out.writeObject(lts);out.writeObject(ishm);out.writeObject(istm);out.writeObject(emps);out.close();//alsoflushoutputstreamDecoratorpatternEmployeemustimplementSerializableRef.《ThinkinginJava,2e》p61353ObjectInputStreamin=newObjectInputStream(newFileInputStream("collect.out"));LinkedListil2=(LinkedList)in.readObject();LinkedListsl2=(LinkedList)in.readObject();LinkedListsll2=(LinkedList)in.readObject();ArrayListda2=(ArrayList)in.readObject();Vectorcv2=(Vector)in.readObject();HashSetshs2=(HashSet)in.readObject();TreeSetlts2=(TreeSet)in.readObject();HashMapishm2=(HashMap)in.readObject();TreeMapistm2=(TreeMap)in.readObject();Setemps2=(Set)in.readObject();in.close();JDK1.4withGenerics

sample.12,serialization(lightweightpersistence)readDecoratorpatternEmployeemustimplementSerializableRef.《ThinkinginJava,2e》p61354LinkedListil2=(LinkedList<Integer>)in.readObject();LinkedList<Integer>il2=(LinkedList<Integer>)in.readObject();

ERRORboth!found:java.lang.Objectrequired:java.util.LinkedList<java.lang.Integer>LinkedList<Integer>il2=(LinkedList)in.readObject();

Warning:uncheckedassignment:java.util.LinkedListtojava.util.LinkedList<java.lang.Integer>LinkedList<Integer>il2=in.readObject();

ERROR!found:java.lang.Objectrequired:java.util.LinkedList<java.lang.Integer>LinkedListil2=(LinkedList)in.readObject();

CORRECT!JDK1.4withGenerics

sample.12,serialization(lightweightpersistence)readERROR!Ref.Test.java55GenericProgramming

inC++classtemplates(語言層次)functiontemplates(語言層次)membertemplates(語言層次)iteratortraits(編程技巧)typetraits(編程技巧)56GenericProgramming

inC++,functiontemplatefind()

template<typenameI,typename

T>I

find(Ibegin,Iend,const

T&value){while(begin!=end&&*begin!=value)

++begin;returnbegin;//invokecopyctor}functiontemplate被呼叫時,編譯器會進行「引數推導」intia[]={0,1,2,3,4,5};list<int>iList(ia,ia+6};list<int>::iteratorite1=iList.begin();list<int>::iteratorite2=iList.end();cout<<*find(ite1,ite2,3);Appclasstemplate被運用時,編譯器不會進行「引數推導」inSTLRef.《STL源碼剖析》p34557GenericProgramming

inC++,functiontemplatefor_each()

for_each(iList.begin(),iList.end(),printElem);Apptemplate<classInputIterator,classFunction>Function

for_each(InputIteratorfirst,InputIteratorlast,

Functionf){for(;first!=last;++first)f(*first);returnf;}(iList見上頁)inSTLRef.《STL源碼剖析》p34958GenericProgramming

inC++,classtemplatelisttemplate<typenameT>structlist_Node

{...};template<typenameT>classlist_Iterator{private:

list_Node<T>*node;};template<typenameT>classlist{public:typedeflist_Iterator<T>iterator;protected:

list_Node<T>*node;...};inSTL59GenericProgramming

inC++,classtemplatelist

42103ilist.nodeilist.begin()ilist.end()環狀雙向串列正向逆向list<int>ilist;Ref.《STL源碼剖析》p13260AssociativeContainersbinder1st,binder2nd,

unary_negate,binary_negate,unary_compose,binary_compose...BasicMutatingAlgorithmsNon-mutatingAlgorithmsSortingandSearchingAlgorithmsArithmeticOperationsComparisonsLogicalOperationsIdentityandProjectionInsertiteratorsStreamiteratorsreverse_iterator演算法

Algorithms容器Containers仿函式

Functors(FunctionObjects)各種Iteratoradapters各種FunctionadaptersSequenceContainers空間配置器

Allocatorsdt::allocatormalloc_allocatordefault_allocatorContainer<T>::iterator迭代器IteratorsC++STLArchitecture

6groupcomponentsRef.《STL源碼剖析》p661C++STLContainers

stackqueuevectorlistdequepriority-queuesetmapmultisetmultimaphash_sethash_maphash_multisethash_multimapheapRB-treearray(build-in)hashtable序列式容器

SequenceContainers關聯式容器

AssociativeContainers非公開非標準非標準非標準非標準非標準配接器(adapter)配接器(adapter)以演算法型式

呈現(xxx_heap)slist非標準C++內建Ref.《STL源碼剖析》p11462C++STLrangeanditerators

half-openrange,egin(),end()begin()end()begin()end()pos++431625pos++Ref.《C++標準程式庫》p84,86,8963C++STLallocator

exquisitememorypoolnextpage...6464bytes64bytes#0#1#2#3#4#5#6#7#8#9#10#11#12#13#14#1532bytes32bytes32bytes32bytes32bytesmemory

poolfree_list[16]它負責32bytes區塊start_freeend_free64bytes64bytes它負責64bytes區塊0096bytes它負責96bytes區塊96bytes96bytes96bytes0第一塊傳

回給客端第一塊傳

回給客端第一塊傳

回給客端這些連續區塊,以unionobj串接起來,形成freelist

的實質組成。圖中的小小箭頭即表示它們形成一個linkedlist。Ref.《STL源碼剖析》p6965Biblio

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论