ASM Java字节码操作框架入门学习 输出Hello World
1.类信息
package org.example;
public class Hello {
public void say(){
System.out.println("hello world");
}
}
查看字节码信息
//动态设置栈大小
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
//设置类的基本信息
classWriter.visit(
V1_8, //设置JDK版本,
ACC_PUBLIC, // 设置权限修饰符,
"Hello", //新类的权限定类名,
null,//泛型
"java/lang/Object", // 父类
null//实现的接口
);
2.无参构造方法
文章来源:https://www.toymoban.com/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); // 调用 return 指令
constructor.visitMaxs(1, 1);//方法的最大栈大小 方法的最大局部变量数
constructor.visitEnd(); //方法结束
3.say 方法
文章来源地址https://www.toymoban.com/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",//方法的描述符,用于描述方法的参数类型和返回值类型
null,//方法泛型
null//可能抛出的异常
);
//获取System.out
methodVisitor.visitFieldInsn(
Opcodes.GETSTATIC,//字段的类型
"java/lang/System",//字段所属类的全限定类名
"out",//指定字段
"Ljava/io/PrintStream;"//字段描述信息
);
//加载常量
methodVisitor.visitLdcInsn("hello world");
methodVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,//方法调用的操作码
"java/io/PrintStream",//方法的权限定类名
"println",//方法名
"(Ljava/lang/String;)V", //方法修饰符
false);//方法调用者是否是接口
methodVisitor.visitInsn(Opcodes.RETURN);
methodVisitor.visitMaxs(2, 0);
methodVisitor.visitEnd();
4.完成类的定义并创建实例调用目标方法
// 完成类的定义
classWriter.visitEnd();
// 将生成的字节码写入文件或加载到内存中
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();
// 调用say方法
helloClass.getMethod("say").invoke(helloObject);
5.相关JVM指令
方法调用
- invokestatic:用于调用静态方法。该指令会根据方法的类名、方法名和方法描述符进行方法查找和调用。
- invokespecial:用于调用私有方法、构造方法和父类方法。该指令会根据方法的类名、方法名和方法描述符进行方法查找和调用。
- invokevirtual:用于调用实例方法。该指令会根据对象的类型和方法的签名进行方法查找和调用。
- invokeinterface:用于调用接口方法。该指令会根据接口的类型和方法的签名进行方法查找和调用。
- invokedynamic:用于调用动态方法。该指令会通过调用动态绑定方法来实现方法的调用
加载常量或数字
- ldc:将常量(包括字符串、整数、浮点数等)加载到操作数栈上。
- ldc_w:与ldc类似,但用于加载较大的常量(超过65535个字节)。
- bipush:将一个字节大小的整数常量(-128到127之间)加载到操作数栈上。
- sipush:将一个短整型常量(-32768到32767之间)加载到操作数栈上。
- iconst_:将整数常量(-1到5之间)加载到操作数栈上,其中为0到5之间的数字。 _
- fconst:将浮点数常量(0.0、1.0和2.0)加载到操作数栈上,其中为0到2之间的数字。
- dconst_:将双精度浮点数常量(0.0和1.0)加载到操作数栈上,其中为0或1。 _
- _ lconst_:将长整型常量(0和1)加载到操作数栈上,其中为0或1
到了这里,关于ASM Java字节码操作框架入门学习 输出Hello World的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!