文章詳情頁
ASM2.0字節(jié)碼框架介紹
瀏覽:106日期:2024-07-19 16:47:51
內(nèi)容: 摘要:Java的特性如動態(tài)類加載和反射使其成為動態(tài)語言。然而在許多時候,反射是不夠的,而且開發(fā)人員需要從非Java源程序中生成字節(jié)碼,如腳本語言Groovy和BeanShell,或者源數(shù)據(jù)如ORM配置。當(dāng)使用已經(jīng)存在的類時,特別是當(dāng)沒有源程序時,就需要使用一些工具來做如分析類或方法的依賴性以便生成測試度量,或者來檢查是否存在問題或反模式。Java5中增加了一些新特性,如如注解和范型,這會影響字節(jié)碼結(jié)果因而需要字節(jié)碼處理工具特別注意以便保持良好的性能。本文會通過一個最小且最快的Java字節(jié)碼處理框架來演示。版權(quán)聲明:任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載時請務(wù)必保留以下作者信息和鏈接作者:Eugene Kuleshov;xMatrix(作者的blog:http://blog.matrix.org.cn/page/xMatrix)原文:http://www.onjava.com/pub/a/onjava/2005/08/17/asm3.html譯文:http://www.matrix.org.cn/resource/article/44/44220_ASM+Bytecode+Framework.html關(guān)鍵字:ASM;Bytecode;Framework框架結(jié)構(gòu)ASM字節(jié)碼處理框架是用Java開發(fā)的而且使用基于訪問者模式生成字節(jié)碼及驅(qū)動類到字節(jié)碼的轉(zhuǎn)換。這允許開發(fā)人員避免直接處理方法字節(jié)碼中的類常量池及偏移,因此為開發(fā)人員隱藏了字節(jié)碼的復(fù)雜性并且相對于其他類似工具如BCEL, SERP, or Javassist提供了更好的性能。ASM分為幾個包更方便靈活地構(gòu)建。包結(jié)構(gòu)圖如圖1。 Figure 1. Arrangement of ASM packages·Core包提供了讀/寫/轉(zhuǎn)換字節(jié)碼的API而且是其他包的基礎(chǔ)。這個包已經(jīng)足夠生成Java字節(jié)碼而且能夠?qū)崿F(xiàn)大部分的字節(jié)碼轉(zhuǎn)換。·Tree包提供了Java字節(jié)碼的內(nèi)存內(nèi)表示。·Analysis包為存儲在來自Tree包結(jié)構(gòu)中的Java方法字節(jié)碼提供了基礎(chǔ)的數(shù)據(jù)流分析和類型檢查算法。·Commons包(ASM2.0增加)提供了幾個通用的字節(jié)碼轉(zhuǎn)換和簡化字節(jié)碼生成的適配器。·Util包包含幾個助手類和簡單的字節(jié)碼較驗器來方便開發(fā)和測試。·XML包提供了與XML文件相互轉(zhuǎn)換的字節(jié)碼結(jié)構(gòu)適配器,及兼容SAX而且允許使用XSLT來定義字節(jié)碼轉(zhuǎn)換方式的適配器。后面幾節(jié)會給出ASM框架中Core包的介紹。為了更好地理解這個包的組織結(jié)構(gòu),你最好有一些在JVM規(guī)范中定義的字節(jié)碼結(jié)構(gòu)的基礎(chǔ)了解。下面是較高級別的類文件格式圖([*]標(biāo)識重復(fù)的結(jié)構(gòu)) [1]-------------------------------------------+ | Header and Constant Stack | +--------------------------------------------+ | [*] Class Attributes | [2]------------+------------------------------+ | [*] Fields | Field Name, Descriptor, etc | | +------------------------------+ | | [*] Field Attributes | [3]------------+------------------------------+ | [*] Methods | Method Name, Descriptor, etc | | +------------------------------| | | Method max stack and locals | | |------------------------------| | | [*] Method Code table | | |------------------------------| | | [*] Method Exception table | | |------------------------------| | | [*] Method Code Attributes | | +------------------------------| | | [*] Method Attributes | +-------------+------------------------------+需要注意的一些地方:·所有使用在類結(jié)構(gòu)中的描述符,字符串和其他常量都存儲在類文件開始的常量堆棧中,來自其他結(jié)構(gòu)的引用是基于堆棧的序號。·每一個類必須包含頭部(包括類名,父類,接口等)和常量堆棧。而其他元素如字段列表/方法列表/屬性列表都是可選的。·每一個方法段包含相同的頭信息和最大最小局部變量數(shù)的信息,這些是用來校驗字節(jié)碼的。對非抽象和非原生方法,還包含一個方法指令表,一個異常表及代碼屬性。此外,還可能有其他的方法屬性。·類的每一個屬性,成員/方法/方法代碼都有自己的名字,具體細節(jié)可參考JVM規(guī)范的類文件格式部分。這些屬性代表字節(jié)碼的各種信息,如源文件名/內(nèi)部類/標(biāo)識(用來存儲泛型)/行號/局部變量表和注解。JVM規(guī)范也允許定義自定義的屬性來包含更多的信息但標(biāo)準(zhǔn)實現(xiàn)的VM不會識別。注:Java5注解實際上已經(jīng)廢棄了那些自定義屬性,因為注解在主義上允許你表達更多的東西。·方法代碼表包含JVM的指令列表。一些指令(就像異常/行號/局部變量表)使用代碼表中的偏移值并且所有這些偏移的值可能需要在指令從方法代碼表中增刪時相應(yīng)調(diào)整。如你所見,字節(jié)碼轉(zhuǎn)換并不容易。但是,ASM框架減少了潛在的結(jié)構(gòu)復(fù)雜性并且提供簡化的API允許所有字節(jié)碼信息的訪問和復(fù)雜的轉(zhuǎn)換。基于事件的字節(jié)碼處理Core包使用推方案(類似訪問者模式,在SAX API就使用了這種模式處理XML)來遍歷復(fù)雜的字節(jié)碼結(jié)構(gòu)。ASM定義了幾個接口,如ClassVisitor,F(xiàn)ieldVisitor,MethodVisitor和AnnotationVisitor。AnnotationVisitor是一個特殊的接口允許你表達層次的注解結(jié)構(gòu)。下面的幾幅圖顯示這些接口是如何相互交互及配合使用實現(xiàn)字節(jié)碼轉(zhuǎn)換和從字節(jié)碼獲取信息。Core包邏輯上可憐分為兩大部分:1、 字節(jié)碼生產(chǎn)者,如ClassReader或者按正確順序調(diào)用了上面的訪問者類的方法的自定義類。2、 字節(jié)碼消費者,如輸出器(ClassWriter, FieldWriter, MethodWriter, and AnnotationWriter),適配器(ClassAdapter and MethodAdapter)或者其他實現(xiàn)了訪問者接口的類。圖2給出了通用生產(chǎn)者/消費者交互過程的時序圖。Figure 2. Sequence diagram for producer-consumer interaction在這個交互過程中,客戶端應(yīng)用首先創(chuàng)建了ClassReader并調(diào)用accept()方法(以ClassVisitor實例作為參數(shù))。然后ClassReader解析類并對每一個字節(jié)碼斷發(fā)送“visit事務(wù)給ClassVisitor。對循環(huán)的上下文,如成員/方法/注解,ClassVisitor可以創(chuàng)建繼續(xù)撲克相應(yīng)接口(FieldVisitor, MethodVisitor, or AnnotationVisitor)的子訪問者并返回給生產(chǎn)者。如果生產(chǎn)者接收到一個空值,他簡單地忽略類的那部分(如在由訪問者驅(qū)動的“延遲加載特性時就不需要解析相應(yīng)的字節(jié)碼部分);否則相應(yīng)的子上下文事件就傳遞給子訪問者實例。當(dāng)子上下文結(jié)束時,生產(chǎn)者調(diào)用visitEnd()方法然后移到下一部分。字節(jié)碼消費者可以通過手工傳遞事件給下一個鏈中的訪問者或者使用來自傳遞所有訪問方法給內(nèi)部的訪問者的ClassAdapter/ MethodAdapter的訪問者通過“響應(yīng)鏈模式連接起來。這些代理者一方面字節(jié)碼的消費者方面另一方面也作為字節(jié)碼的生產(chǎn)者。他們在實現(xiàn)特定的字節(jié)碼轉(zhuǎn)換時可以修改原始的代理方式:1、 訪問調(diào)用代理可以在刪除類成員/方法/方法指令時被忽略。2、 訪問調(diào)用參數(shù)可以在重命名類/方法/類型時被修改。3、 新訪問調(diào)用可以在引入新成員/方法/注入新代碼到現(xiàn)存代碼時被增加。ClassWriter訪問者可以終結(jié)整個處理鏈,他也是最終字節(jié)碼的生成者。例如: ClassWriter cw = new ClassWriter(computeMax); ClassVisitor cc = new CheckClassAdapter(cw); ClassVisitor tv = new TraceClassVisitor(cc, new PrintWriter(System.out)); ClassVisitor cv = new TransformingClassAdapter(tv); ClassReader cr = new ClassReader(bytecode); cr.accept(cv, skipDebug); byte[] newBytecode = cw.toByteArray();在上面的代碼中,實現(xiàn)了自定義的類轉(zhuǎn)換并且將結(jié)果人作為參數(shù)傳給TraceClassVisitor的構(gòu)造函數(shù)。TraceClassVisitor打印轉(zhuǎn)換的類并傳遞給CheckClassAdapter(這是用來作簡單的字節(jié)校驗后傳遞給ClassWriter)。大部分的訪問方法接收簡單的參數(shù)如int,boolean和String。在所有的方法中String參數(shù)是字節(jié)碼中常量的引用,ASM使用與JVM一致的方式。例如,所有類名都應(yīng)該定義在內(nèi)部格式中。成員和方法描述符應(yīng)該跟JVM表示一致。泛型信息的表示也類似。這種方式避免了在沒有轉(zhuǎn)換時不必要的計算。為了便于構(gòu)建和解析這樣的描述,系統(tǒng)提供了包含一些靜態(tài)方法的Type類:·String getMethodDescriptor(Type returnType, Type[] argumentTypes)·String getInternalName(Class c)·String getDescriptor(Class c)·String getMethodDescriptor(Method m)·Type getType(String typeDescriptor)·Type getType(Class c)·Type getReturnType(String methodDescriptor)·Type getReturnType(Method m)·Type[] getArgumentTypes(String methodDescriptor)·Type[] getArgumentTypes(Method m)注意這些描述符使用了“簡單表示,這意味著不包含泛型信息。泛型信息實際上作為一個單獨的字節(jié)屬性存儲,但ASM專門對待這個屬性并且在相應(yīng)訪問方法中傳遞泛型標(biāo)識串作為參數(shù)。這個標(biāo)識串的值也是參照J(rèn)VM規(guī)范,與Java代碼中的泛型定義唯一映射,并且為工具增加獲取額外細節(jié)的機會。ASM提供了與其他訪問者類似的SignatureVisitor, SignatureReader, and SignatureWriter類,如圖3所示。 Figure 3. Sequence diagram for Signature classesUtil包中包含了TraceSignatureVisitor,已經(jīng)實現(xiàn)了SignatureVisitor而且可以將一個標(biāo)識值轉(zhuǎn)換成Java的泛型定義。下面的例子將一個方法標(biāo)識轉(zhuǎn)換為Java方法定義。 TraceSignatureVisitor v = new TraceSignatureVisitor(access); SignatureReader r = new SignatureReader(sign); r.accept(v); String genericDecl = v.getDeclaration(); String genericReturn = v.getReturnType(); String genericExceptions = v.getExceptions(); String methodDecl = genericReturn + ' ' + methodName + genericDecl; if(genericExceptions!=null) { methodDecl += ' throws ' + genericExceptions; }到目前為止,我們已經(jīng)討論了ASM框架的基本設(shè)計方式及類結(jié)構(gòu)處理。但最有趣的部分是ASM如何處理方法代碼。訪問方法代碼在ASM中,方法定義是由ClassVisitor.visitMethod()來表示,剩下的方法字節(jié)碼則由MethodVisitor中的許多訪問方法來表示。這些方法按照下面的順序來調(diào)用,“*表示重復(fù)的方法而“?表示方法只能被調(diào)用一次。此外,visit...Insn 和visitLabel方法必須按照訪問代碼的字節(jié)碼指令順序調(diào)用,而visitTryCatchBlock, visitLocalVariable和visitLineNumber方法必須在標(biāo)簽作為參數(shù)傳遞被訪問后才能調(diào)用。注意visitEnd方法必須在方法處理完成后被調(diào)用。雖然ClassReader已經(jīng)做了這一步,但在使用自定義字節(jié)碼生產(chǎn)者時要注意一點。還要注意如果一個方法包含字節(jié)碼(也就是說方法是非抽象或非源生的),那么visitCode必須在第一個visit...Insn調(diào)用前被調(diào)用,而visitMaxs必須在最后一個visit...Insn調(diào)用后被調(diào)用。每一個visitIincInsn, visitLdcInsn, visitMultiANewArrayInsn, visitLookupSwitchInsn, and visitTableSwitchInsn方法唯一對應(yīng)一個字節(jié)碼指令。剩下的visit...Insn方法對應(yīng)多個字節(jié)碼指令,他們的操作碼作為第一個方法參數(shù)被傳入。所有這些操作碼常量被定義在Opcodes接口中。這種方式對字節(jié)碼的解析和格式化非常有效率。不幸的是,這給開發(fā)人員生成非法代碼的可能,因為ClassWriter不會校驗這些限制。但是,還是有一個CheckClassAdapter可以被用來在開發(fā)期間測試生成的代碼。另一個機會是對所有字節(jié)碼生成或轉(zhuǎn)換可以修改方法代碼的偏移并且在方法代碼中增刪額外的指令時應(yīng)該自動調(diào)整。這對所有的跳轉(zhuǎn)偽指令的參數(shù)都兼容的,就如try-catch塊,行號和局部變量定義及一些特殊屬性一樣。但是,ASM為開發(fā)人員隱藏了這些復(fù)雜性。為了定義方法字節(jié)碼中的位置且不需要使用絕對偏移值,需要傳遞一個唯一的標(biāo)簽類的實例給visitLabel方法。其他MethodVisitor方法如visitJumpInsn, visitLookupSwitchInsn, visitTableSwitchInsn, visitTryCatchBlock, visitLocalVariable, and visitLineNumber可以使用這些標(biāo)簽實例在visitLabel調(diào)用之前,就像實例后在方法后被調(diào)用。上面的內(nèi)容看起來很復(fù)雜,好像需要很深奧的字節(jié)碼指令知識。但是在編譯的類上使用ASMifierClassVisitor就可以讓你知道如何用ASM生成給定的字節(jié)碼。此外,在兩個編譯的類上(一個原始的和另一個應(yīng)用特定的轉(zhuǎn)換)使用然后進行比較就可以給出什么樣的ASM調(diào)用應(yīng)該被使用在轉(zhuǎn)換器上。這個過程在幾篇文章中已經(jīng)詳細解釋了(可以參看最后的資源部分)。目前已經(jīng)有了Eclipse使用的插件了,如圖4,提供了從Java源生成ASM代碼及比較ASMifier輸出的良好支持,還包含了上下文字節(jié)碼的參考。 Figure 4. Eclipse ASM plugin (Click on the picture to see a full-size image)用ASM的訪問者來跟蹤類的依賴已經(jīng)有一些文章介紹了如何用ASM生成字節(jié)碼。現(xiàn)在,我們來看一下如何用ASM分析已有的類。我們來做一個有趣的應(yīng)用來獲取給定的.jar文件中使用的外部類和包。簡單起見,這個例子僅獲取外部的依賴而不會取依賴的類型(如父類/方法參數(shù)/局部變量類型等)。僅為分析,我們不會創(chuàng)建那些注解/成員/方法的子訪問者實例。所有使用的訪問者(包括類和標(biāo)識訪問者)都在一個類中實現(xiàn):public class DependencyVisitor implements AnnotationVisitor, SignatureVisitor, ClassVisitor, FieldVisitor, MethodVisitor {...在這個例子中,我們會跟蹤包之間的依賴,因此私有類必須包含包名: private String getGroupKey(String name) { int n = name.lastIndexOf('/'); if(n>-1) name = name.substring(0, n); packages.add(name); return name; }為了獲取依賴關(guān)系,訪問者接口如ClassVisitor, AnnotationVisitor, FieldVisitor, and MethodVisitor應(yīng)該選擇性地集成方法的參數(shù)。幾個常見的樣例如下: private void addName(String name) { if(name==null) return; String p = getGroupKey(name); if(current.containsKey(p)) { current.put(p, current.get(p)+1); } else { current.put(p, 1); } }在這個例子中,current是依賴的當(dāng)前包。另一個例子是類型描述符(注解/枚舉/成員類型/newarray指令的參數(shù)等);如Ljava/lang/String;, J, and [[[I。這些可以用Type.getType( desc)來獲取內(nèi)部格式的類名: private void addDesc(String desc) { addType(Type.getType(desc)); } private void addType(Type t) { switch(t.getSort()) { case Type.ARRAY: addType(t.getElementType()); break; case Type.OBJECT: addName(t.getClassName().replace('.','/')); break; } }在方法定義中的方法描述法及激活指令中的描述參數(shù)類型及返回類型。可以通過Type.getReturnType(methodDescriptor) 和Type.getArgumentTypes(methodDescriptor)來解析并取得參數(shù)和返回類型。 private void addMethodDesc(String desc) { addType(Type.getReturnType(desc)); Type[] types = Type.getArgumentTypes(desc); for(int i = 0; i < types.length; i++) { addType(types[ i]); } }而使用在許多“訪問方法中的用來定義Java5泛型信息的標(biāo)識參數(shù)是個特例。如果存在,這個參數(shù)重寫描述符參數(shù)并包含編碼后的泛型信息。可以被用SignatureReader來解析這個值。所以我們可以實現(xiàn)SignatureVisitor來被每一個標(biāo)識工件來調(diào)用。 private void addSignature(String sign) { if(sign!=null) { new SignatureReader(sign).accept(this); } } private void addTypeSignature(String sign) { if(sign!=null) { new SignatureReader(sign).acceptType(this); } }實現(xiàn)ClassVisitor接口的方法,如such as visit(), visitField(), visitMethod(), and visitAnnotation()就可以獲取在父類/接口/成員類型/方法參數(shù)/返回值/異常上的依賴信息,就如注解一樣。例如: public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { String p = getGroupKey(name); current = groups.get(p); if(current==null) { current = new HashMap(); groups.put(p, current); } if(signature==null) { addName(superName); addNames(interfaces); } else { addSignature(signature); } } public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { if(signature==null) { addDesc(desc); } else { addTypeSignature(signature); } if(value instanceof Type) { addType((Type) value); } return this; } public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { if(signature==null) { addMethodDesc(desc); } else { addSignature(signature); } addNames(exceptions); return this; } public AnnotationVisitor visitAnnotation( String desc, boolean visible) { addDesc(desc); return this; }實現(xiàn)MethodVisitor接口的方法就可以獲取關(guān)于參數(shù)注解類型和使用在可以使用對象引用的字節(jié)碼指令上的依賴: public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { addDesc(desc); return this; } /** * Visits a type instruction * NEW, ANEWARRAY, CHECKCAST or INSTANCEOF. */ public void visitTypeInsn(int opcode, String desc) { if(desc.charAt(0)=='[') { addDesc(desc); } else { addName(desc); } } /** * Visits a field instruction * GETSTATIC, PUTSTATIC, GETFIELD or PUTFIELD. */ public void visitFieldInsn(int opcode, String owner, String name, String desc) { addName(owner); addDesc(desc); } /** * Visits a method instruction INVOKEVIRTUAL, * INVOKESPECIAL, INVOKESTATIC or * INVOKEINTERFACE. */ public void visitMethodInsn(int opcode, String owner, String name, String desc) { addName(owner); addMethodDesc(desc); } /** * Visits a LDC instruction. */ public void visitLdcInsn(Object cst) { if(cst instanceof Type) { addType((Type) cst); } } /** * Visits a MULTIANEWARRAY instruction. */ public void visitMultiANewArrayInsn( String desc, int dims) { addDesc(desc); } /** * Visits a try catch block. */ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { addName(type); }現(xiàn)在我們可以用DependencyVisitor來獲取整個.jar文件的依賴關(guān)系了。例如: DependencyVisitor v = new DependencyVisitor(); ZipFile f = new ZipFile(jarName); Enumeration<? extends ZipEntry> en = f.entries(); while(en.hasMoreElements()) { ZipEntry e = en.nextElement(); String name = e.getName(); if(name.endsWith('.class')) { ClassReader cr = new ClassReader(f.getInputStream(e)); cr.accept(v, false); } }可以用很多不同的方式來表示得到的信息。一種方式是構(gòu)建依賴樹并計算相關(guān)數(shù)據(jù)或者創(chuàng)建可視化的東西。例如,圖5顯示了ant1.6.5 jar包中的依賴關(guān)系的可視化表現(xiàn),這是我使用一些簡單的Java2D代碼寫的。下面的圖在水平軸上顯示包,在垂直軸上顯示依賴。陰影部分表示包被多次引用。 Figure 5. Dependencies in ant.1.6.5.jar, as discovered with ASM這個工具的全部代碼會被包含在下一個ASM發(fā)布中。你可以從ASM CVS獲取。ASM1.x后的改變?nèi)绻銢]有使用ASM1.x可以略過這個段。2.0中主要的結(jié)構(gòu)變化是所有J2SE5.0的特性都被內(nèi)建到訪問者/過濾器的事件流中。因此新的API允許你用更輕便和自然的方式來處理泛型和注解。不需要顯式創(chuàng)建注解屬性實例,因為在事件流中已經(jīng)包含了泛型和注解數(shù)據(jù)。例如,在1.x,ClassVisitor接口如下使用: CodeVisitor visitMethod(int access, String name, String desc, String[] exceptions, Attribute attrs);This has been split into several methods in ASM 2.0:在2.0中已經(jīng)分為多個方法: MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) AnnotationVisitor visitAnnotation(String desc, boolean visible) void visitAttribute(Attribute attr)在1.x API中,為了定義泛型信息,你必須創(chuàng)建SignatureAttribute的實例,而定義注解你需要RuntimeInvisibleAnnotations, RuntimeInvisibleParameterAnnotations, RuntimeVisibleAnnotations, RuntimeVisibleParameterAnnotations, and AnnotationDefault的實例。然后你可以將這些實例放在相應(yīng)的訪問方法的attrs參數(shù)中。在2.0,增加了新的標(biāo)識參數(shù)來表示泛型信息。新的AnnotationVisitor接口被用來處理所有的注解。不再需要創(chuàng)建attrs集合了,而且注解數(shù)據(jù)是強類型的。然而在移植現(xiàn)有代碼時,特別是在“適配器類被使用時,必須注意確保所有來自適配器的方法需要重寫來適應(yīng)新的標(biāo)識,因為編譯器不用對這種情況給出警告。ASM2.0還有些其他的改變。1、增加了新的接口FieldVisitor 和AnnotationVisitor2、CodeVisitor合并到MethodVisitor中了。3、在MethodVisitor中增加了visitCode()方法簡化檢測首個指令。4、Constants接口重構(gòu)為Opcodes。5、所有來自attrs包的屬性被包含到ASM的事件模型中。6、TreeClassAdapter and TreeCodeAdapter被包含到ClassNode and MethodNode中。7、增加LabelNode類使指令集合的元素成為AbstractInsnNode的通用類型。通常,建議使用如JDiff這樣的工具來比較兩個版本之間的區(qū)別。小結(jié)ASM2.0為開發(fā)人員屏蔽了字節(jié)碼的復(fù)雜性,因而使開發(fā)人員更有效在字節(jié)碼級別上使用Java的特性。這個框架不僅允許你轉(zhuǎn)換和生成字節(jié)碼,而且可以從現(xiàn)有的類中取得具體的信息。他的API繼續(xù)改善,現(xiàn)在已經(jīng)包含了J2SE5.0中的泛型和注解。接下來,還會增加Mustang(J2SE6)中的新特性。資源·Java Virtual Machine Specification Java虛擬機規(guī)范•·'“修訂的類文件格式(JVM規(guī)范的第4章)。包含J2SE5.0中支持的JSR-14/JSR-175/JSR-201中要求的修改及其他小的更正和調(diào)整。·“使用ASM工具集來處理字節(jié)碼·“使用ASM工具集來創(chuàng)建和讀寫J2SE5.0注解·字節(jié)碼指令(BCI)。Eugene Kuleshov是一個獨立咨詢師,擁有超過15年的軟件設(shè)計開發(fā)經(jīng)驗。 Java, java, J2SE, j2se, J2EE, j2ee, J2ME, j2me, ejb, ejb3, JBOSS, jboss, spring, hibernate, jdo, struts, webwork, ajax, AJAX, mysql, MySQL, Oracle, Weblogic, Websphere, scjp, scjd 摘要:Java的特性如動態(tài)類加載和反射使其成為動態(tài)語言。然而在許多時候,反射是不夠的,而且開發(fā)人員需要從非Java源程序中生成字節(jié)碼,如腳本語言Groovy和BeanShell,或者源數(shù)據(jù)如ORM配置。當(dāng)使用已經(jīng)存在的類時,特別是當(dāng)沒有源程序時,就需要使用一些工具來做如分析類或方法的依賴性以便生成測試度量,?
相關(guān)文章:
1. 淺談java中字節(jié)與字符的區(qū)別2. Java StringBuilder類相關(guān)知識總結(jié)3. java substring(a)與substring(a,b)的使用說明4. 關(guān)于Java中String創(chuàng)建的字符串對象內(nèi)存分配測試問題5. Python 的 f-string 可以連接字符串與數(shù)字的原因解析6. java實現(xiàn)Object轉(zhuǎn)String的4種方法小結(jié)7. 對String的深刻理解8. java字符串格式化(String類format方法)9. Java實用工具之StringJoiner詳解10. SQL注入寬字節(jié)注入由淺到深學(xué)習(xí)
排行榜
