1、簡述java
用於生成和轉換編譯後的java類,動態生成java 字節碼,生成class文件。數組
2、使用描述3d
編譯後的java類包含如下幾部分:
一個用於描述修飾符(public或者private),類名,父類名稱,所實現的接口名稱以及類註解的段。
一個用於描述類中字段信息的段。每一個這樣的段中都描述了字段的修飾符,名稱,類型以及與該字段相關的註解。
一個用於描述方法和構造方法的段。每一個段描述了方法的名稱,返回值,參數類型以及方法的註解。同時也包含了方法編譯後的字節碼序列。blog
在源代碼和編譯後的代碼之間,仍是存在一些不一樣:
一個編譯後的java類僅僅只描述一個類信息,可是一個java源文件能夠包含幾個java類。例如,一個源文件能夠定義一個包含內部類的java類,而編譯後將會成爲兩個類文件,其中一個是主要的java類,另一個是內部類。在主要的類中包含了指向內部類的引用,同時在主要的java類的方法中定義的內部類也會包含一個指向該java方法的引用。
一個編譯後的java類不包含註釋,固然,能夠包含與類、字段、方法或者代碼相關的屬性,而這些屬性能夠用來關聯一些額外的信息。在java 5中引入了註解之後,這些註解也能夠實現一樣的目的,所以,這些屬性就變得不那麼重要了。
一個編譯後的java類不包含package和import段,所以,在編譯後的類中,全部的類型名稱都必須使用全路徑。接口
類的具體結構請參看java虛擬機規範第四段事件
編譯後的java類總體結構(*表示0或者更多)文檔
2.1.2內部名稱
在不少狀況下,一個類型限於一個java類或者結構表示的類型,例如,一個類的父類,一個類所實現的接口,一個方法所拋出的異常(不多是基本類型)或者數組,這些都是類或者接口類型。這些類型在編譯後的類中之內部名稱表示。一個類的內部名稱就是這個類的全路徑名稱,將包名中的點號替換爲/。例如,String的內部名稱爲java/lang/String。字符串
2.1.3類型描述符
內部名稱僅用做一個類或者接口的類型,全部其餘的,如字段類型,java基本類型都是以類型描述符來表示的,見圖2.2
類型描述符:虛擬機
基本類型的描述符:Z表示boolean,C表示char,B表示byte,I表示int,F表示float,J表示long,D表示double。一個類的描述符就是這個類的內部名稱,在前面加上一個L,在後面加上一個分號便可。例如,String的類型描述符就是Ljava/lang/String.最後,一個數組的類型描述符就是一箇中括號[後面跟上數組元素的類型描述符。it
2.1.4方法描述符
一個方法描述符就是一個包含參數類型的描述符,以及方法返回類型描述符的字符串。一個方法描述符以一個左括號開始,而後跟上每一個參數的描述符,而後是一個右括號,最後就是返回值的類型描述符,若是一個方法的返回值是void,那麼返回值的類型描述符就是V(一個方法描述符不包含這個方法的名稱以及參數的名稱)。
方法描述符示例
一旦你知道了類型描述符如何工做,那麼理解方法描述符很容易。例如,(I)I描述了這樣一個方法,它有一個int類型的參數,以及一個int返回值。圖2.3給出了幾個方法描述符的例子。
2.2接口和組件
2.2.1表現(Presentation)
生成和轉換編譯後的類的ASM API是基於ClassVisitor接口的(見圖2.4)。在這個接口中的每個方法都與類文件中有着相同名稱的段相對應(見圖2.1)。在訪問類結構中簡單的段時,是經過調用一個獨立的方法來實現的,該方法的參數就是該段相關的內容,該方法的返回值爲void。對長度任意而且較複雜的段進行訪問時,是經過一個初始化方法返回一個輔助的visitor接口來實現,例如visitAnnotation,visitField以及visitMethod,它們都返回與之對應的接口AnnotationVisitor,FieldVisitor以及MethodVisitor。
這些規則也一樣適用於這些輔助接口。例如,在FieldVisitor接口中的每一個方法,都與類文件結構中與該名稱(Field)對應的子結構對應(見圖2.5),而且visitAnnotation並會一個輔助的AnnotationVisitor接口,與ClassVisitor中的AnnotationVisitor相同。關於這些輔助接口的建立和使用,將在下一章節介紹,這一章主要限於那些簡單的問題,使用ClassVisitor接口就能夠解決的。
圖2.4 ClassVisitor接口
圖2.5 FieldVisitor接口
對ClassVisitor接口中方法的調用必須遵循下面文檔定義的順序,該文檔定義在ClassVisitor 接口的Javadoc中。 visit visitSource? visitOuterClass? ( visitAnnotation | visitAttribute )*( visitInnerClass | visitField | visitMethod )* visitEnd 這就意味着visit必須被第一個調用,而後調用visitSource方法,最多調用一次,再接着是visitOuterClass,而後再調用任意次數的visitAnnotation或者visitAttribute方法,接着能夠調用任意次數的visitInnerClass,visitiField或者visitMethod,順序不限,在最後,調用visitEnd方法。 在ClassVisitor接口的基礎上,ASM提供了三個組件來生成和轉換類: ClassReader 用來解析編譯過的class的字節數組。而後,調用ClassVisitor實例的visitXxx方法,其中ClassVisitor實例做爲ClassReader.accept方法的參數傳遞進去的。ClassReader能夠被看作是一個事件產生者。 ClassWriter是ClassVisitor接口的一個實現,用來以二進制方式構建編譯後的類。它產生一個包含編譯後的類的字節數組,能夠經過它的toByteArray方法來或得。它能夠被看作是一個事件消費者。 ClassAdapter也是ClassVisitor接口的一個實現,它將對它的方法調用委託給另外一個ClassVisitor。它能夠被認爲是一個事件過濾器。 接下來,將結合具體的例子來展現如何使用這些組件來生成和轉換類。