ASM Java字節(jié)碼操作框架入門學(xué)習(xí) 輸出Hello World
1.類信息
package org.example;
public class Hello {
public void say(){
System.out.println("hello world");
}
}
查看字節(jié)碼信息
//動態(tài)設(shè)置棧大小
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//設(shè)置類的基本信息
classWriter.visit(
V1_8, //設(shè)置JDK版本,
ACC_PUBLIC, // 設(shè)置權(quán)限修飾符,
"Hello", //新類的權(quán)限定類名,
null,//泛型
"java/lang/Object", // 父類
null//實現(xiàn)的接口
);
2.無參構(gòu)造方法
文章來源:http://www.zghlxwxcb.cn/news/detail-539725.html
0 aload_0
1 invokespecial #1 <java/lang/Object.<init> : ()V>
4 return
MethodVisitor constructor = classWriter.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
constructor.visitVarInsn(Opcodes.ALOAD, 0); //操作局部變量表 局部變量表第一個存放this
constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
constructor.visitInsn(Opcodes.RETURN); // 調(diào)用 return 指令
constructor.visitMaxs(1, 1);//方法的最大棧大小 方法的最大局部變量數(shù)
constructor.visitEnd(); //方法結(jié)束
3.say 方法
文章來源地址http://www.zghlxwxcb.cn/news/detail-539725.html
0 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
3 ldc #3 <hello world>
5 invokevirtual #4 <java/io/PrintStream.println : (Ljava/lang/String;)V>
8 return
//添加say方法
MethodVisitor methodVisitor = classWriter.visitMethod(ACC_PUBLIC,//方法修飾符號
"say",//方法名
"()V",//方法的描述符,用于描述方法的參數(shù)類型和返回值類型
null,//方法泛型
null//可能拋出的異常
);
//獲取System.out
methodVisitor.visitFieldInsn(
Opcodes.GETSTATIC,//字段的類型
"java/lang/System",//字段所屬類的全限定類名
"out",//指定字段
"Ljava/io/PrintStream;"http://字段描述信息
);
//加載常量
methodVisitor.visitLdcInsn("hello world");
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,//方法調(diào)用的操作碼
"java/io/PrintStream",//方法的權(quán)限定類名
"println",//方法名
"(Ljava/lang/String;)V", //方法修飾符
false);//方法調(diào)用者是否是接口
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(2, 0);
methodVisitor.visitEnd();
4.完成類的定義并創(chuàng)建實例調(diào)用目標(biāo)方法
// 完成類的定義
classWriter.visitEnd();
// 將生成的字節(jié)碼寫入文件或加載到內(nèi)存中
byte[] bytecode = classWriter.toByteArray();
ClassLoader classLoader = new ClassLoader() {
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
return defineClass(name, bytecode, 0, bytecode.length);
}
};
// 加載并實例化Hello類
Class<?> helloClass = classLoader.loadClass("Hello");
Object helloObject = helloClass.getDeclaredConstructor().newInstance();
// 調(diào)用say方法
helloClass.getMethod("say").invoke(helloObject);
5.相關(guān)JVM指令
方法調(diào)用
- invokestatic:用于調(diào)用靜態(tài)方法。該指令會根據(jù)方法的類名、方法名和方法描述符進行方法查找和調(diào)用。
- invokespecial:用于調(diào)用私有方法、構(gòu)造方法和父類方法。該指令會根據(jù)方法的類名、方法名和方法描述符進行方法查找和調(diào)用。
- invokevirtual:用于調(diào)用實例方法。該指令會根據(jù)對象的類型和方法的簽名進行方法查找和調(diào)用。
- invokeinterface:用于調(diào)用接口方法。該指令會根據(jù)接口的類型和方法的簽名進行方法查找和調(diào)用。
- invokedynamic:用于調(diào)用動態(tài)方法。該指令會通過調(diào)用動態(tài)綁定方法來實現(xiàn)方法的調(diào)用
加載常量或數(shù)字
- ldc:將常量(包括字符串、整數(shù)、浮點數(shù)等)加載到操作數(shù)棧上。
- ldc_w:與ldc類似,但用于加載較大的常量(超過65535個字節(jié))。
- bipush:將一個字節(jié)大小的整數(shù)常量(-128到127之間)加載到操作數(shù)棧上。
- sipush:將一個短整型常量(-32768到32767之間)加載到操作數(shù)棧上。
- iconst_:將整數(shù)常量(-1到5之間)加載到操作數(shù)棧上,其中為0到5之間的數(shù)字。 _
- fconst:將浮點數(shù)常量(0.0、1.0和2.0)加載到操作數(shù)棧上,其中為0到2之間的數(shù)字。
- dconst_:將雙精度浮點數(shù)常量(0.0和1.0)加載到操作數(shù)棧上,其中為0或1。 _
- _ lconst_:將長整型常量(0和1)加載到操作數(shù)棧上,其中為0或1
到了這里,關(guān)于ASM Java字節(jié)碼操作框架入門學(xué)習(xí) 輸出Hello World的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!