本文重点看一下如何使用asm生成类、字段、方法。我们还是采用循环渐进的方式进行讲解,首先定义一个类,然后观察类对应的字节码方法以及指令集,最终使用asm进行生成即可。
定义一个类,如下所示:
public class Person { private int age; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int add(int a, int b) { return a + b; } }
1.生成Person类:
ClassWriter cw=new ClassWriter(0);
//生成类public 类名ShareniuGenerateClasses 继承Object类
cw.visit(V1_8, ACC_PUBLIC, "ShareniuGenerateClasses", null, "java/lang/Object", null);
注意:ShareniuGenerateClasses类是我们以Person为模板生成的类。
2.生成age字段:
cw.visitField(ACC_PRIVATE, "age", "I", null, null).visitEnd();
3.生成getAge方法:
getAge方法的指令如下:
0: aload_0
1: getfield
4: ireturn
示例代码如下:
//首先生成方法
MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "getAge", "()I", null, null); // 方法访问开始 mv.visitCode(); //aload_0 mv.visitVarInsn(ALOAD, 0); //getfield mv.visitFieldInsn(Opcodes.GETFIELD, "ShareniuGenerateClasses", "age", "I"); //ireturn mv.visitInsn(IRETURN); mv.visitMaxs(2, 2); mv.visitEnd();
mv.visitVarInsn(ALOAD, 0); 加载this
GETFIELD:获取指定的字段。
4.生成setAge(int age)方法:
setAge方法的指令如下:
0: aload_0
1: iload_1
2: putfield
5: return
示例代码如下:
mv = cw.visitMethod(ACC_PUBLIC, "setAge", "(I)V", null, null); // 方法访问开始 mv.visitCode(); // aload_0 mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitFieldInsn(PUTFIELD, "ShareniuGenerateClasses", "age", "I"); mv.visitInsn(RETURN); mv.visitMaxs(2, 2); mv.visitEnd();
5.生成 add(int a, int b)方法:
add(int a, int b)方法的指令如下:
0: iload_1
1: iload_2
2: iadd
3: ireturn
示例代码如下:
mv = cw.visitMethod(ACC_PUBLIC, "add", "(II)I", null, null); mv.visitVarInsn(Opcodes.ILOAD, 1); mv.visitVarInsn(Opcodes.ILOAD, 2); mv.visitInsn(IADD); mv.visitInsn(IRETURN); mv.visitMaxs(3, 3); mv.visitEnd(); cw.visitEnd();
6.生成构造方法:
要不然到时候执行字节码的时候报错:
mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); mv.visitInsn(RETURN); mv.visitMaxs(1, 1); mv.visitEnd();
7.执行生成的字节码:
示例代码如下:
byte[] toByte = cw.toByteArray();// byt 和toByte其实是相同的数组 GenerateClasses3 classLoader = new GenerateClasses3(); Class<?> clazz = classLoader.defineClass("ShareniuGenerateClasses", cw.toByteArray(), 0, toByte.length); Method addMethod = clazz.getMethod("add", int.class, int.class); Object result = addMethod.invoke(clazz.newInstance(), 10, 20); if (result != null && result instanceof Integer) System.out.println((Integer) result);
不出意外的话,程序的输出是30。
转载请注明:分享牛 » 使用asm生成类以及方法