Classworking工具箱泛型與ASM知識講解_第1頁
Classworking工具箱泛型與ASM知識講解_第2頁
Classworking工具箱泛型與ASM知識講解_第3頁
Classworking工具箱泛型與ASM知識講解_第4頁
Classworking工具箱泛型與ASM知識講解_第5頁
已閱讀5頁,還剩24頁未讀, 繼續(xù)免費閱讀

下載本文檔

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

文檔簡介

1、Good is good, but better carries it.精益求精,善益求善。Classworking工具箱泛型與ASM-Java5泛型提供了對于許多classworking都非常有用的信息。盡管Java反射可用于為載入的類獲取泛型信息,但要求類必須載入到JVM中,這是一個很大的缺點。在本文中,classworking精神領(lǐng)袖DennisSosnoski展示了ASMJava字節(jié)碼操縱框架怎樣在無需經(jīng)過Javaclassloading處理的情況下提供對泛型信息的靈活訪問。在文中,他還深入探討了泛型的二進(jìn)制類表示。Java5程序中的泛型信息對于理解程序的數(shù)據(jù)結(jié)構(gòu)非常有幫助。在HYPE

2、RLINK/developerworks/cn/java/j-cwt11085.html上一期中,我為您介紹了如何使用運行時反射來訪問泛型信息。如果您僅對獲得載入JVM中的類的信息感興趣,那么這種反射方法非常有效。但有時您可能希望在載入類之前對其加以修改,或者希望在不載入類的情況下研究數(shù)據(jù)結(jié)構(gòu)。在這樣的時候,反射對您來說就不再是一種行之有效的辦法反射將JVM類結(jié)構(gòu)作為信息源使用,因此它僅對已由JVM裝載的類起作用。要想在不將類載入JVM的情況下訪問泛型信息,您需要一種讀取存儲在二進(jìn)制類表示內(nèi)的泛型信息的方法。在前幾期文章中,已經(jīng)介紹過ASMclassworking庫是怎樣提供了一種清潔的接口,

3、以讀取及寫入二進(jìn)制類。在這篇文章中,我將向您展示如何利用ASM從類文件中獲取原始泛型信息,如何以一種有用的方式解釋泛型。在鉆研ASP細(xì)節(jié)之前,讓我們首先來看看泛型信息編碼到二進(jìn)制類中的實際方式。跟蹤泛型為將可由Java編譯器使用的鍵入信息添加到Java二進(jìn)制類中,需要使用泛型規(guī)范設(shè)計器。幸運的是,Java平臺已有一種內(nèi)置于二進(jìn)制類格式中的機(jī)制,可用于此目的。這種機(jī)制就是屬性結(jié)構(gòu)(attributestructure),它主要使所有類型的信息可與類本身或類的方法、字段及其他組件相關(guān)聯(lián)。某些類型的屬性信息是由JVM規(guī)范定義的,但Java語言的原始設(shè)計器作出了明智的選擇,將一組可能出現(xiàn)的屬性保留為開

4、放,從而可由新版本的規(guī)范加以擴(kuò)展,也可由用戶擴(kuò)展以設(shè)計其自己的自定義屬性。泛型信息存儲在一個新的標(biāo)準(zhǔn)屬性中:簽名屬性。該屬性是一個簡單的文本值,為類、字段、方法或變量解碼泛型信息。更新的Java5JVM規(guī)范(HYPERLINK/developerworks/cn/java/j-cwt02076.htmllresources#resources參考資料部分給出了Java5更改頁面的鏈接)清楚地說明了簽名文本值的完整語法。在這里我不打算加以詳述,但本節(jié)稍后的部分中會簡單介紹簽名。首先將介紹一些必備的背景信息,以使您了解類名稱的內(nèi)部結(jié)構(gòu)及JVM所使用的字段和方法描述符。深入內(nèi)部Java平臺中的類總是

5、來自某些包。當(dāng)您在Java源代碼中引用類名稱時,您或許會也或許不會真正將包限定作為名稱的一部分。您總是可以包含包限定(形如java.lang.String),但您也可以為了省事而忽略它如果類來自java.lang包或已import到源文件中。這種包含包限定的類名稱結(jié)構(gòu)就稱為“完全限定”類名。在實際的二進(jìn)制類內(nèi)部,類名稱總是在一個包中指定的。但這種名稱的格式與Java源代碼中的完全限定類名略有差別,使用正斜杠(“/”)取代圓點(“.”)。例如,在String類中,名稱的內(nèi)部形式為java/lang/String。如果您嘗試將一個類文件作為文本輸出或查看,那么通常會看到上述形式的多個字符串,每個字

6、符串都是對某個類的引用。采用這種內(nèi)部形式的類引用是作為字段和方法描述符的一部分使用的。字段描述符指定類中定義的一個類的準(zhǔn)確類型。所使用的表示法取決于字段是簡單對象類型、簡單原語類型還是數(shù)組類型。簡單對象類型的表示法為,以L開頭,后接對象類名稱的內(nèi)部形式,以;結(jié)尾。原語類型的表示法為,各類型使用一個單獨的字母(如I表示int、Z表示布爾型)。數(shù)組類型的表示法為,以作為數(shù)組項類型(其本身也可為數(shù)組類型)的前綴修飾符。表1給出了關(guān)于各字段描述符的示例,另外還列出了相應(yīng)的Java源代碼聲明:表1.字段描述符示例描述符源代碼Ljava/lang/String;StringIintLjava/lang/O

7、bject;ObjectZbooleanLcom/sosnoski/generics/FileInfo;com.sosnoski.generics.FileInfo方法描述符結(jié)合了字段描述符,以指定方法的參數(shù)類型和返回類型。方法描述符的格式非常易于理解。以(開始,后接參數(shù)的字段描述符(均一起運行),隨后是),最后以返回類型結(jié)尾(若返回類型為void,則以V結(jié)尾)。表2給出了方法描述符的一些示例,同時還列出了相應(yīng)的Java源代碼聲明(注意方法名稱和參數(shù)名稱本身并非方法描述符的一部分,所以在表中使用了占位符):表2.方法描述符示例描述符源代碼(Ljava/lang/String;)Iintmmm(

8、Stringx)(ILjava/lang/String;)Vvoidmmm(intx,Stringy)(I)Ljava/lang/String;Stringmmm(intx)(Ljava/lang/String;)Ccharmmm(Stringx)(ILjava/lang/String;Lcom/sosnoski/generics/FileInfo;)Vvoidmmm(intx,Stringy,FileInfoz)在虛線處簽名上面已經(jīng)介紹了字段和方法描述符,那么接下來將介紹簽名。簽名格式擴(kuò)展了字段和方法描述符的概念,將泛型類型信息包含于其中。不幸的是,泛型的復(fù)雜性(包括可能出現(xiàn)的各種上下界變化

9、等)意味著簽名無法像描述符那樣簡單地說明。簽名的語法(詳見JVMspecificationchangesforJava1.5的第4章)包含21個獨立產(chǎn)品項。本文無法全面涉及,這里將給出幾個示例,下一節(jié)將針對這部分示例展開講解。清單1是HYPERLINK/developerworks/cn/java/j-cwt11085.html上一期文章中所用的一個數(shù)據(jù)結(jié)構(gòu)類的部分源代碼,以及相應(yīng)的簽名字符串。在本例中,類本身并非參數(shù)化類型,但字段和方法使用了參數(shù)化的java.util.List:清單1.簡單的簽名示例publicclassDirInfoprivatefinalListm_files;priv

10、atefinalListm_directories;.publicListgetDirectories()returnm_directories;publicListgetFiles()returnm_files;.Classsignature:nonem_filessignature:Ljava/util/List;m_directoriessignature:Ljava/util/List;getDirectories()signature:()Ljava/util/List;getFiles()signature:()Ljava/util/List;由于類并非參數(shù)化類型,所以未為該類本身

11、的二進(jìn)制類表示添加任何簽名。但確實為使用參數(shù)化類型的字段和方法使用了簽名。m_files字段簽名表示這是一個List,且類型為FileInfo;而m_directories字段簽名則表示這是一個類型為DirInfo的List。同樣,getDirectories()方法簽名表示該方法返回一個類型為DirInfo的List,而getFiles()簽名則表示該方法返回一個類型為FileInfo的List。迄今為止,一切看起來都相當(dāng)容易理解,但事實真是如此嗎?下面讓我們看看清單2,其中給出了一個簡單的參數(shù)化類定義和相應(yīng)的簽名字符串:清單2.參數(shù)化類簽名示例publicclassPairCollecti

12、onimplementsIterable/*Collectionwithfirstcomponentvalues.*/privatefinalArrayListm_tValues;/*Collectionwithsecondcomponentvalues.*/privatefinalArrayListm_uValues;.publicvoidadd(Tt,Uu)m_tValues.add(t);m_uValues.add(u);publicUget(Tt)intindex=m_tValues.indexOf(t);if(index=0)returnm_uValues.get(index);el

13、sereturnnull;.Classsignature:Ljava/lang/Object;Ljava/lang/Iterable;m_tValuessignature:Ljava/util/ArrayList;m_uValuessignature:Ljava/util/ArrayList;addsignature:(TT;TU;)Vgetsignature:(TT;)TU;由于清單2中的類為參數(shù)化類型,所以類簽名需要以二進(jìn)制類形式表示。與源代碼相比,簽名的文本要長一些,但如果您了解到,源代碼中省略的類型參數(shù)的所有可選組件都包含在簽名中,那么理解起來也就不太困難了。簽名的第一部分(位于尖括號

14、內(nèi))就是該類的類型參數(shù)定義清單。這些定義的形式都相同,類型參數(shù)名稱后接類型的類邊界和接口邊界(若存在)的字段描述符。各字段描述符前加:字符。由于清單2源代碼未為類的類型參數(shù)指定任何邊界,因此其邊界均為默認(rèn)的類邊界java.lang.Object。類簽名的第二部分(尖括號外)給出了超類和超接口(若存在)的簽名。在清單2所示的例子中,未指定任何超類,因此簽名以java.lang.Object作為超類。這里指定了超接口,為Iterable。在簽名中可以看到預(yù)期結(jié)果,源代碼中使用的只是,而簽名中使用的是。原因在于簽名需要區(qū)分類名稱和類型變量名稱,第一個T標(biāo)識緊隨其后的內(nèi)容為類型變量名,而結(jié)尾的;表示名

15、稱結(jié)束。HYPERLINK/developerworks/cn/java/j-cwt02076.htmllcode2#code2清單2中的字段和方法簽名利用了與超接口簽名相同的變量格式類型,其他都與前面介紹的內(nèi)容相同。HYPERLINK/developerworks/cn/java/j-cwt02076.htmllmain#main回頁首ASM中的泛型本系列的前幾期文章中已介紹過(鏈接參見HYPERLINK/developerworks/cn/java/j-cwt02076.htmllresources#resources參考資料部分),ASM使用了一種訪問器(visitor)模式來處理二進(jìn)制

16、類表示。這種訪問器模式是雙向的:您可以解析一個現(xiàn)有類,得到類組件的處理程序訪問器方法的調(diào)用序列,也可以實現(xiàn)對類寫入器的訪問器方法的同類調(diào)用序列,以生成一個二進(jìn)制類表示。這一解析器/寫入器對稱使ASM在您僅修改類的特定方面的情況下尤為方便您可將類寫入器作為類解析器事件的處理程序的基礎(chǔ),僅重寫基寫入器來處理您想更改的事件。解析器(或讀取器)和寫入器都是非常有用的獨立組件。ASM2.X全面支持Java5JVM更改,包括讀取和寫入簽名。簽名的基本處理是通過直接傳遞給恰當(dāng)?shù)脑L問器方法的值自動實現(xiàn)的。另外,ASM2.X還增加了對簽名字符串(有時非常復(fù)雜)編碼進(jìn)行解析的支持,從而可翻譯簽名細(xì)節(jié)。按照ASM的

17、基本原理,相同的接口還可供寫入器使用以按需生成簽名字符串。在這一節(jié)中,我將介紹ASM如何將基本簽名作為textblob處理,又是如何詳細(xì)解析基本簽名的。所有部分的簽名ASM中將簽名作為textblob處理,這一方式直接內(nèi)建于基本類、字段和方法的訪問器調(diào)用中。清單3展示了org.objectweb.asm.ClassVisitor接口中的相應(yīng)方法:清單3.類、字段和方法的訪問器方法publicinterfaceClassVisitorvoidvisit(intversion,intaccess,Stringname,Stringsignature,StringsuperName,Stringin

18、terfaces);FieldVisitorvisitField(intaccess,Stringname,Stringdesc,Stringsignature,Objectvalue);MethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,Stringsignature,Stringexceptions);.清單中的各訪問器方法將簽名字符串作為參數(shù)。若相應(yīng)的類、字段或方法非泛型,則在調(diào)用方法時將返回null值。清單4顯示了簽名相關(guān)方法的實際應(yīng)用。其中用mons.EmptyVisitor類作為基礎(chǔ)實現(xiàn)了一個訪問器類,這樣我只需重寫想使

19、用的方法即可。所提供的方法實現(xiàn)僅輸出整體簽名信息、本清單所示類中各字段和方法的描述符和簽名信息。清單4的末尾處展示了在HYPERLINK/developerworks/cn/java/j-cwt02076.htmllcode1#code1清單1所示的完整DirInfo類中使用此訪問器時所生成的輸出:清單4.簽名相關(guān)方法的實際應(yīng)用publicclassShowSignaturesVisitorextendsEmptyVisitorpublicvoidvisit(intversion,intaccess,Stringname,Stringsig,Stringsname,Stringinames)S

20、ystem.out.println(Class+name+signature:);System.out.println(+sig);super.visit(version,access,name,sig,sname,inames);publicFieldVisitorvisitField(intaccess,Stringname,Stringdesc,Stringsig,Objectvalue)System.out.println(Field+name+descriptorandsignature:);System.out.println(+desc);System.out.println(+

21、sig);returnsuper.visitField(access,name,desc,sig,value);publicMethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,Stringsig,Stringexceptions)System.out.println(Method+name+()descriptorandsignature:);System.out.println(+desc);System.out.println(+sig);returnsuper.visitMethod(access,name,desc,sig,

22、exceptions);Classcom/sosnoski/generics/DirInfosignature:nullFieldm_filesdescriptorandsignature:Ljava/util/List;Ljava/util/List;Fieldm_directoriesdescriptorandsignature:Ljava/util/List;Ljava/util/List;Fieldm_lastModifydescriptorandsignature:Ljava/util/Date;nullMethod()descriptorandsignature:(Ljava/io

23、/File;)VnullMethodgetDirectories()descriptorandsignature:()Ljava/util/List;()Ljava/util/List;MethodgetFiles()descriptorandsignature:()Ljava/util/List;()Ljava/util/List;MethodgetLastModify()descriptorandsignature:()Ljava/util/Date;null簽名分析除將簽名作為字符串處理外,ASM還支持在細(xì)節(jié)級處理簽名。org.objectweb.asm.signature.Signat

24、ureReader類解析一個簽名字符串,并生成對org.objectweb.asm.signature.SignatureVisitor接口的調(diào)用序列。org.objectweb.asm.signature.SignatureWriter類實現(xiàn)訪問器接口,并從訪問器方法調(diào)用序列中構(gòu)建出簽名字符串。很不幸,細(xì)節(jié)級接口有些復(fù)雜,但其原因在于簽名定義的復(fù)雜性,而不是ASM代碼處理不力。SignatureVisitor接口展現(xiàn)了這一復(fù)雜性,它定義了16個可在簽名處理過程中包含的獨立方法調(diào)用。當(dāng)然,絕大多數(shù)簽名僅使用這些方法中的一小部分。為舉例說明ASM的細(xì)節(jié)級簽名處理,我將解析本文前面所討論的某些簽名

25、,從而介紹方法。為此,我編寫了TraceSignatureVisitor類,清單5展示了該類的部分代碼,該清單中的AnalyzeSignaturesVisitor用于驅(qū)動簽名處理。當(dāng)AnalyzeSignaturesVisitor用做類的訪問器時,它會為所發(fā)現(xiàn)的各簽名創(chuàng)建一個SignatureReader,將TraceSignatureVisitor類的一個實例作為簽名組件訪問器調(diào)用的目標(biāo)傳遞。用于解析簽名的SignatureReader調(diào)用取決于簽名的形式:對于類和方法簽名,恰當(dāng)?shù)姆椒ㄊ莂ccept();對于字段簽名,應(yīng)使用acceptType()調(diào)用。清單5.簽名分析publicclass

26、TraceSignatureVisitorimplementsSignatureVisitorpublicvoidvisitFormalTypeParameter(Stringname)System.out.println(visitFormalTypeParameter(+name+);publicSignatureVisitorvisitClassBound()System.out.println(visitClassBound();returnthis;publicSignatureVisitorvisitInterfaceBound()System.out.println(visitI

27、nterfaceBound();returnthis;publicSignatureVisitorvisitSuperclass()System.out.println(visitSuperclass();returnthis;publicSignatureVisitorvisitInterface()System.out.println(visitInterface();returnthis;publicSignatureVisitorvisitParameterType()System.out.println(visitParameterType();returnthis;.publicc

28、lassAnalyzeSignaturesVisitorextendsEmptyVisitorpublicvoidvisit(intversion,intaccess,Stringname,Stringsig,Stringsname,Stringinames)if(sig!=null)System.out.println(Class+name+signature:);System.out.println(+sig);newSignatureReader(sig).accept(newTraceSignatureVisitor();super.visit(version,access,name,

29、sig,sname,inames);publicFieldVisitorvisitField(intaccess,Stringname,Stringdesc,Stringsig,Objectvalue)if(sig!=null)System.out.println(Field+name+signature:);System.out.println(+sig);newSignatureReader(sig).acceptType(newTraceSignatureVisitor();returnsuper.visitField(access,name,desc,sig,value);public

30、MethodVisitorvisitMethod(intaccess,Stringname,Stringdesc,Stringsig,Stringexceptions)if(sig!=null)System.out.println(Method+name+()signature:);System.out.println(+sig);newSignatureReader(sig).accept(newTraceSignatureVisitor();returnsuper.visitMethod(access,name,desc,sig,exceptions);清單6顯示了使用AnalyzeSig

31、naturesVisitor類訪問HYPERLINK/developerworks/cn/java/j-cwt02076.htmllcode1#code1清單1中的DirInfo類時所生成的輸出:清單6.DirInfo代碼和簽名分析publicclassDirInfoprivatefinalListm_files;privatefinalListm_directories;.publicListgetDirectories()returnm_directories;publicListgetFiles()returnm_files;.Fieldm_filessignature:Ljava/ut

32、il/List;visitClassType(java/util/List)visitTypeArgument(=)visitClassType(com/sosnoski/generics/FileInfo)visitEnd()visitEnd()Fieldm_directoriessignature:Ljava/util/List;visitClassType(java/util/List)visitTypeArgument(=)visitClassType(com/sosnoski/generics/DirInfo)visitEnd()visitEnd()MethodgetDirector

33、ies()signature:()Ljava/util/List;visitReturnType()visitClassType(java/util/List)visitTypeArgument(=)visitClassType(com/sosnoski/generics/DirInfo)visitEnd()visitEnd()MethodgetFiles()signature:()Ljava/util/List;visitReturnType()visitClassType(java/util/List)visitTypeArgument(=)visitClassType(com/sosno

34、ski/generics/FileInfo)visitEnd()visitEnd()清單6中輸出行的第一塊展示了m_files簽名Ljava/util/List;的分析過程中所調(diào)用的訪問器方法。第一個方法調(diào)用是visitClassType(java/util/List),給出了字段的基類。隨后visitTypeArgument(=)說明實際類型由當(dāng)前類的類型參數(shù)(java.util.List)提供,visitClassType(com/sosnoski/generics/FileInfo)說明實際類型以com.sosnoski.generics.FileInfo為基礎(chǔ)。最終,對visitEnd

35、()的第一個調(diào)用關(guān)閉了打開的FileInfo類簽名,第二個調(diào)用關(guān)閉了打開的List類簽名。通過觀察訪問器方法調(diào)用序列,您或許已經(jīng)猜到,其中部分調(diào)用有效地為嵌入的類型簽名組件打開了一個新的上下文。SignatureVisitor接口中返回SignatureVisitor實例的方法均有此作用。方法調(diào)用所返回的接口實例(可能與被調(diào)用的實例相同,也可能不同,HYPERLINK/developerworks/cn/java/j-cwt02076.htmllcode5#code5清單5代碼中就是相同的)隨后用于處理嵌入的類型簽名??珊苋菀椎貙YPERLINK/developerworks/cn/java

36、/j-cwt02076.htmllcode5#code5清單5所示代碼作出修改,以縮進(jìn)格式展示子簽名嵌套,本文提供的下載文件中也包含更改后的代碼。這里不準(zhǔn)備給出詳細(xì)的代碼,僅介紹輸出結(jié)果。清單7給出了在HYPERLINK/developerworks/cn/java/j-cwt02076.htmllcode2#code2清單2的PairCollection參數(shù)化類上運行此縮進(jìn)版代碼時所生成的輸出結(jié)果(部分):清單7.PairCollection代碼和簽名分析publicclassPairCollectionimplementsIterable/*Collectionwithfirstcomponentvalues.*/privatefinalArrayListm_tValues;/*Collectionwithsecondcomponentvalues.*/privatefinalArrayListm_uValues;.publicvoidadd(Tt,Uu)m_tValues.add(t);m_uValues.add(u);publicUget(Tt)intindex=m_tValues.indexOf(t);if(index=0)returnm_uValues.get(index);elsereturnnull;.Classcom/sosn

溫馨提示

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

評論

0/150

提交評論