前言
ASM式操作字节码的工具类,可以生成,解析,改变字节码的信息。
我们要生成的类和字节码信息
使用ASM生成该类
生成字节码需要了解字节码的基本信息,我会出一篇博客专门介绍,并添加连接,这里不做赘述。第一篇作为入门大家了解一下,代码注释清晰,请自行查看。
导入的jar包
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.1</version>
</dependency>
生成该类的主要逻辑
public class GenerateClass {
public void generate(String name){
ClassWriter cw = new ClassWriter(0);
// 此处实现了一个接口,这个不是必须的,因为下面不想使用
cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, name, null, "java/lang/Object", new String[]{"com/wenbin/asm/generate/MyInterface"});
cw.visitField(Opcodes.ACC_PUBLIC, "age", "I", "", null).visitEnd();
// 构造器
MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null);
// 押入第一个参数this到栈顶
constructor.visitVarInsn(Opcodes.ALOAD, 0);
// 调用object的构造器
constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
// 押入第一个参数this到栈顶
constructor.visitVarInsn(Opcodes.ALOAD, 0);
// 把23押入栈顶
constructor.visitVarInsn(Opcodes.BIPUSH, 23);
// 为指定类的实例域赋值
constructor.visitFieldInsn(Opcodes.PUTFIELD, name, "age", "I");
// 返回构造出的实例
constructor.visitInsn(Opcodes.RETURN);
// 设置栈深度和局部变量表的大小
constructor.visitMaxs(2, 1);
constructor.visitEnd();
// 实现接口的方法
MethodVisitor getInt = cw.visitMethod(Opcodes.ACC_PUBLIC, "getAge", "()I", null, null);
// 押入第一个参数this到栈顶
getInt.visitVarInsn(Opcodes.ALOAD, 0);
// 获取值并压入栈顶
getInt.visitFieldInsn(Opcodes.GETFIELD, name, "age", "I");
// 返回栈顶的值
getInt.visitInsn(Opcodes.IRETURN);
getInt.visitMaxs(1, 1);
getInt.visitEnd();
// 结束符号
cw.visitEnd();
// 把该类的字节码放入到map中储存,加载使用
Constant.classFile.put(name, cw.toByteArray());
}
注意
这里只粘贴出了生成的主要代码,截止到cw.visitEnd();。调用生成的类,使用到的接口等,粘贴出来后也表达不清楚,请到gitee中查看。
其中涉及到一些类加载器的知识,请先阅读之前的博客查看。