盘古BPM体验地址    盘古BPM交流群盘古BPM交流群号:963222735

使用asm生成类以及方法

分享牛 3097℃


本文重点看一下如何使用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生成类以及方法