class(二)使用ASM动态生成class文件

前言
  • JVM在运行时,加载并执行class文件,这个class文件是由编写好的java源文件经过javac编译而得到。
  • 有时候会遇到一种情况,前期编写程序时不知道要写什么类,只有到运行时,才能根据当时的程序执行状态知道要使用什么类。
    • 常见的处理方式可以使用JDK中的动态代理
    • 还有一个叫做ASM的库,能够直接生成class文件,它的api对于动态代理来说更加原生,每个api都和class文件格式中的特定部分吻合。

动态生成如下class文件:

public class AsmDemo11 {

    public static void main(String[] var0) {
        System.out.println("Hello ASM 123");
    }
}

1.使用ASM框架动态生成java类和main方法

添加依赖:

    //ASM依赖
    implementation 'org.ow2.asm:asm:7.2'
    implementation 'org.ow2.asm:asm-commons:7.2'

代码实现:

public class MyClass extends ClassLoader implements Opcodes {

    public static void main(String[] args) throws Exception {
        System.out.println("-----MyClass----");
        //定义一个类模版
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_7, ACC_PUBLIC, "AsmDemo11", null, "java/lang/Object", null);

        //TODO 1构造默认构造函数
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
                "",
                "()V",
                null, null);
        //生成构造函数字节码指令 -- 加载操作
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL,
                "java/lang/Object",
                "",
                "()V",
                false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        //TODO 2.构造main函数
        mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
                "main",
                "([Ljava/lang/String;)V",
                null,
                null);

        //TODO 3.main方法中生成 System.out.println("Hello ASM");
        //获取System类中的属性  System.out --    public static final PrintStream out;
        mv.visitFieldInsn(GETSTATIC,
                "java/lang/System",
                "out",
                "Ljava/io/PrintStream;");

        //栈帧中 属性入栈
        mv.visitLdcInsn("Hello ASM 123");
        //加载 println 方法
        mv.visitMethodInsn(INVOKEVIRTUAL,
                "java/io/PrintStream",
                "println",
                "(Ljava/lang/String;)V",
                false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();

        //todo 4.获取生成的class 文件对应的二进制流
        byte[] codes = cw.toByteArray();

        //将二进制流写入到本地磁盘上
        FileOutputStream fos = new FileOutputStream("AsmDemo11.class");
        fos.write(codes);
        fos.close();

        //反射调用
        MyClass loader = new MyClass();
        Class defineClass = loader.defineClass("AsmDemo11", codes, 0, codes.length);
        defineClass.getMethods()[0].invoke(null, new Object[]{null});
    }
}

日志打印结果:
-----MyClass----
Hello ASM 123

代码解析

1.使用ClassWriter定义一个类
        //定义一个类模版
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_7, ACC_PUBLIC, "AsmDemo11", null, "java/lang/Object", null);
  • ClassWriter的visit方法定义一个类
    - 参数1:V1_7 - 是生成class的版本号,对应class文件中的主版本号和次版本号,
    - 参数2:ACC_PUBLIC - 表示该类的访问标识。这是一个public类,对应class文件的access_flags
    - 参数3:生成类的类名,需要传入全类名。对应class文件中的this_class
    - 参数4:表示泛型,传入null表示这不是一个泛型类。对那个class文件中的Signature属性(attribute)
    - 参数5:当前类的父类的全限类名。该类直接继承自Object。对应class文件中的super_class
    - 参数6:表示当前生成类的直接实现接口,为string[]类型,可以实现多个接口。这个类没有实现任何接口,所以传入null。敌营class文件中的interfaces
2.定义默认构造函数
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
                "",
                "()V",
                null, null);
        //生成构造函数字节码指令 -- 加载操作
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL,
                "java/lang/Object",
                "",
                "()V",
                false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
  • 调用ClassWriter的visitMethod方法返回一个MethodVisitor对象,该对象定义了一个方法,对应class文件中的一个method_info
    • 参数1:ACC_PUBLIC - 指定生成方法的访问标志,对应method_info中的access_flags
    • 参数2:方法的方法名。构造方法名为< init >,对应method_info中的name_index,引用常量池中的方法名字符串
    • 参数3:方法描述符,因为生成的构造方法无入参和无返回值,所以方法描述符为()V.对应method_info中的descriptor_index
    • 参数4:泛型相关,传入nulli表示该方法不是泛型方法。对应method_info中的Signature属性
    • 参数5:指定方法声明可能抛出的异常。传入null表示无异常声明抛出。对应method_info中的Exceptions属性
  • 接着调用MethodVisitor中的方法,生成当前构造方法的字节码,对应method_info中的Code属性
    • 调用visitVarInsn方法,生成aload指令,将第0个本地变量(也就是this)压入操作数栈
    • 调用visitMethodInsn方法,生成invokespecial指令,调用父类(也就是Object)的构造方法
    • 调用visitInsn 方法,生成return指令,方法返回
    • 调用visitMaxs 方法,指定当前要生成方法的最大局部变量和最大操作数栈。对应Code属性中的max_stack和 max_locals
    • 最后调用visitEnd 方法,表示当前要生成的构造方法已经创建完成
3.定义main方法,并生成main方法中的字节码指令
        mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
                "main",
                "([Ljava/lang/String;)V",
                null,
                null);

        //TODO 3.main方法中生成 System.out.println("Hello ASM");
        //获取System类中的属性  System.out --    public static final PrintStream out;
        mv.visitFieldInsn(GETSTATIC,
                "java/lang/System",
                "out",
                "Ljava/io/PrintStream;");

        //栈帧中 属性入栈
        mv.visitLdcInsn("Hello ASM 123");
        //加载 println 方法
        mv.visitMethodInsn(INVOKEVIRTUAL,
                "java/io/PrintStream",
                "println",
                "(Ljava/lang/String;)V",
                false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(2, 2);
        mv.visitEnd();

2.ASM动态生成类和字段,并给字段加上注解

  • 最后实现效果
package com.timmy.asmstudy;

import com.sun.istack.internal.NotNull;

public class Person {
    @NotNull
    public String name;
}

  • 该类对应的字节码
package asm.com.timmy.asmstudy;

import java.util.*;

import org.objectweb.asm.*;

public class AsmDemoDump implements Opcodes {

    public static byte[] dump() throws Exception {

        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;

        cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "com/timmy/asmstudy/AsmDemo", null, "java/lang/Object", null);

        cw.visitSource("AsmDemo.java", null);

        {
            mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(3, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
            mv.visitInsn(RETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lcom/timmy/asmstudy/AsmDemo;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(6, l0);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitLdcInsn("Hello ASM");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(7, l1);
            mv.visitInsn(RETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}

  • 使用ASM动态生成类Person.java和该类里面的name属性
/**
 * 动态生成如上诉Person类
 * 1。使用ClassWrite创建定义Person类
 * 2。生成构造函数
 * 3。生成属性 name
 */
public class BeanTest extends ClassLoader {

    public static void main(String[] args) throws Exception {
        //定义类
        ClassWriter cw = new ClassWriter(0);
        cw.visit(V1_7,
                ACC_PUBLIC + ACC_SUPER,
                "com/timmy/asmstudy/Person11",
                null,
                "java/lang/Object",
                null);

        //构造函数
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC,
                "",
                "()V",
                null,
                null);

        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL,
                "java/lang/Object",
                "",
                "()V",
                false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();

        //构建属性name
        FieldVisitor fv = cw.visitField(ACC_PUBLIC,
                "name11",
                "Ljava/lang/String;",
                null,
                null);
        {
            //为属性添加注解
            AnnotationVisitor av0 = fv.visitAnnotation(
                    "Lcom/sun/istack/internal/NotNull;",
                    false);
            av0.visitEnd();
        }
        fv.visitEnd();

        //生成并加载调用
        byte[] bytes = cw.toByteArray();
        BeanTest beanTest = new BeanTest();
        Class aClass = beanTest.defineClass(null, bytes, 0, bytes.length);

        //使用classLoader加载好后,存在内存中,通过反射创建对象
        Object beanObj = aClass.getConstructor().newInstance();
        //拿到属性 --并设置值
        Field field = aClass.getField("name11");
        field.set(beanObj, "zzzzzzz");

        String nameVal = (String) field.get(beanObj);
        System.out.println("name value:" + nameVal);
    }
}

打印结果:
> Task :AsmStudy:BeanTest.main()
name value:zzzzzzz

3.ASM核心api解析

  • ClassReader类:字节码的读取与分析引擎,采用事件读取机制,每当有事件发生时,调用注册的ClassVisitor,AnnotationVisitor,FieldVisitor,MethodVisitor做相应的处理
  • ClassVisitor类:定义在读取Class字节码时会触发的事件,如类头解析完成,注解解析,字段解析,方法解析等
  • AnnotationVisitor类:定义在解析注解时会触发的事件,如解析到一个基本值类型的注解,enum值类型的注解,注解值类型的注解等
  • FieldVisitor类:定义在解析字段时触发的事件,如解析到字段相关的属性等
  • MethodVisitor类:定义在解析方法时触发的事件,如方法上的注解,属性,代码等
  • ClassWriter等:实现了ClassVisitor抽象类,用于拼接字节码
3.1.ClassReader
org.objectweb.asm.ClassReader

public class ClassReader {

        //构造函数
    public ClassReader(final byte[] b) {
        this(b, 0, b.length);
    }

    public ClassReader(final byte[] b, final int off, final int len) {
       ...
    }

        //核心方法
    public void accept(final ClassVisitor classVisitor, final int flags) {
        accept(classVisitor, new Attribute[0], flags);
    }

    public void accept(final ClassVisitor classVisitor,
            final Attribute[] attrs, final int flags) {
        ...

        // visits the class declaration --1.访问class文件的描述,文件头,版本等信息
        classVisitor.visit(readInt(items[1] - 7), access, name, signature,
                superClass, interfaces);

        // visits the source and debug info --2.访问class资源信息
        if ((flags & SKIP_DEBUG) == 0
                && (sourceFile != null || sourceDebug != null)) {
            classVisitor.visitSource(sourceFile, sourceDebug);
        }

        // visits the module info and associated attributes --3.访问模块信息
        if (module != 0) {
            readModule(classVisitor, context, module,
                    moduleMainClass, packages);
        }
        
        // visits the outer class --4.访问外部类
        if (enclosingOwner != null) {
            classVisitor.visitOuterClass(enclosingOwner, enclosingName,
                    enclosingDesc);
        }

        // visits the class annotations and type annotations --5.访问类的注解
        if (anns != 0) {
            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        classVisitor.visitAnnotation(readUTF8(v, c), true));
            }
        }
        ...

        // visits the attributes --6.访问类的属性
        while (attributes != null) {
            Attribute attr = attributes.next;
            attributes.next = null;
            classVisitor.visitAttribute(attributes);
            attributes = attr;
        }

        // visits the inner classes --7.访问内部类
        if (innerClasses != 0) {
            int v = innerClasses + 2;
            for (int i = readUnsignedShort(innerClasses); i > 0; --i) {
                classVisitor.visitInnerClass(readClass(v, c),
                        readClass(v + 2, c), readUTF8(v + 4, c),
                        readUnsignedShort(v + 6));
                v += 8;
            }
        }

        // visits the fields and methods --8-9.访问字段和方法
        u = header + 10 + 2 * interfaces.length;
        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
            u = readField(classVisitor, context, u);
        }
        u += 2;
        for (int i = readUnsignedShort(u - 2); i > 0; --i) {
            u = readMethod(classVisitor, context, u);
        }

        // visits the end of the class --10.访问类信息结束
        classVisitor.visitEnd();
    }

    //访问类的字段
    private int readField(final ClassVisitor classVisitor,
            final Context context, int u) {
        ...

        // visits the field declaration
        FieldVisitor fv = classVisitor.visitField(access, name, desc,
                signature, value);
        if (fv == null) {
            return u;
        }

        // visits the field annotations and type annotations
        if (anns != 0) {
            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        fv.visitAnnotation(readUTF8(v, c), true));
            }
        }
        if (ianns != 0) {
            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        fv.visitAnnotation(readUTF8(v, c), false));
            }
        }
        if (tanns != 0) {
            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        fv.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), true));
            }
        }
        if (itanns != 0) {
            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        fv.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), false));
            }
        }

        // visits the field attributes
        while (attributes != null) {
            Attribute attr = attributes.next;
            attributes.next = null;
            fv.visitAttribute(attributes);
            attributes = attr;
        }

        // visits the end of the field
        fv.visitEnd();

        return u;
    }

    //访问类中的方法
    private int readMethod(final ClassVisitor classVisitor,
            final Context context, int u) {
        ...

        // visits the method declaration
        MethodVisitor mv = classVisitor.visitMethod(context.access,
                context.name, context.desc, signature, exceptions);
        if (mv == null) {
            return u;
        }

        if (mv instanceof MethodWriter) {
            MethodWriter mw = (MethodWriter) mv;
            if (mw.cw.cr == this && signature == mw.signature) {
                boolean sameExceptions = false;
                if (exceptions == null) {
                    sameExceptions = mw.exceptionCount == 0;
                } else if (exceptions.length == mw.exceptionCount) {
                    sameExceptions = true;
                    for (int j = exceptions.length - 1; j >= 0; --j) {
                        exception -= 2;
                        if (mw.exceptions[j] != readUnsignedShort(exception)) {
                            sameExceptions = false;
                            break;
                        }
                    }
                }
                if (sameExceptions) {
                    /*
                     * we do not copy directly the code into MethodWriter to
                     * save a byte array copy operation. The real copy will be
                     * done in ClassWriter.toByteArray().
                     */
                    mw.classReaderOffset = firstAttribute;
                    mw.classReaderLength = u - firstAttribute;
                    return u;
                }
            }
        }

        // visit the method parameters
        if (methodParameters != 0) {
            for (int i = b[methodParameters] & 0xFF, v = methodParameters + 1; i > 0; --i, v = v + 4) {
                mv.visitParameter(readUTF8(v, c), readUnsignedShort(v + 2));
            }
        }

        // visits the method annotations
        if (dann != 0) {
            AnnotationVisitor dv = mv.visitAnnotationDefault();
            readAnnotationValue(dann, c, null, dv);
            if (dv != null) {
                dv.visitEnd();
            }
        }
        if (anns != 0) {
            for (int i = readUnsignedShort(anns), v = anns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        mv.visitAnnotation(readUTF8(v, c), true));
            }
        }
        if (ianns != 0) {
            for (int i = readUnsignedShort(ianns), v = ianns + 2; i > 0; --i) {
                v = readAnnotationValues(v + 2, c, true,
                        mv.visitAnnotation(readUTF8(v, c), false));
            }
        }
        if (tanns != 0) {
            for (int i = readUnsignedShort(tanns), v = tanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        mv.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), true));
            }
        }
        if (itanns != 0) {
            for (int i = readUnsignedShort(itanns), v = itanns + 2; i > 0; --i) {
                v = readAnnotationTarget(context, v);
                v = readAnnotationValues(v + 2, c, true,
                        mv.visitTypeAnnotation(context.typeRef,
                                context.typePath, readUTF8(v, c), false));
            }
        }
        if (mpanns != 0) {
            readParameterAnnotations(mv, context, mpanns, true);
        }
        if (impanns != 0) {
            readParameterAnnotations(mv, context, impanns, false);
        }

        // visits the method attributes
        while (attributes != null) {
            Attribute attr = attributes.next;
            attributes.next = null;
            mv.visitAttribute(attributes);
            attributes = attr;
        }

        // visits the method code
        if (code != 0) {
            mv.visitCode();
            readCode(mv, context, code);
        }

        // visits the end of the method
        mv.visitEnd();

        return u;
    }
}

  • 源码解析
    • 构造函数参数为byte[]数组,该数组即为字节码内容,后面操作的数据都是基于该数据
    • accept()方法,第1个参数是ClassVisitor,这个方法中定义了ClassVisitor访问class文件内容的顺序
      1. classVisitor.visit() --访问class文件的描述,文件头,版本等信息
      2. classVisitor.visitSource() --访问class资源信息
      3. classVisitor.visitModule() --访问模块信息
      4. classVisitor.visitOuterClass() --访问外部类
      5. classVisitor.visitAnnotation() -- 访问类的注解
      6. classVisitor.visitAttribute() --访问类的属性
      7. classVisitor.visitInnerClass() --访问内部类
      8. readField() — 访问类的字段
      9. readMethod() — 访问类中的方法
      10. classVisitor.visitEnd() —类结构访问结束
    • 类中字段访问流程 readField
      1. FieldVisitor fv = classVisitor.visitField() —访问类中的的字段,并返回一个FieldVisitor对象
      2. fv.visitAnnotation() —访问字段的注解
      3. fv.visitAttribute() —访问字段属性
      4. fv.visitEnd() — 字段访问结束
    • 访问类中方法流程 — readMethod
      1. MethodVisitor mv = classVisitor.visitMethod() —开始访问类中的方法,并返回一个MethodVisitor对象
      2. mv.visitParameter() — 访问方法中的入参
      3. AnnotationVisitor dv = mv.visitAnnotationDefault() — 访问方法的注解
      4. mv.visitAttribute(attributes) —访问方法的属性
      5. mv.visitCode(); —ASM开始扫描这个方法
      6. readCode(mv, context, code); — 访问方法的指令
      7. mv.visitMaxs() — 在visitEnd之前反复调用,去定类方法在执行时堆栈大小
      8. mv.visitEnd(); — 访问方法结束
3.2.ClassWriter详解
  • 源码ClassWriter继承自ClassVisitor,首先看ClassVisitor类中的重要方法
public abstract class ClassVisitor {
  
  protected final int api;
  protected ClassVisitor cv;
  
  public ClassVisitor(final int api) {}
  public ClassVisitor(final int api, final ClassVisitor classVisitor) {}

  public void visit() {}

  public void visitSource() {}

  public ModuleVisitor visitModule() {}

  public void visitNestHost(final String nestHost) {}

  public void visitOuterClass() {}

  public AnnotationVisitor visitAnnotation() {}

  public AnnotationVisitor visitTypeAnnotation() {}

  public void visitAttribute(final Attribute attribute) {}

  public void visitNestMember(final String nestMember) {}

  public void visitInnerClass() {}

  public FieldVisitor visitField() {}

  public MethodVisitor visitMethod() {}

  public void visitEnd() {}
}

3.3.MethodVisitor源码
org.objectweb.asm.MethodVisitor

public abstract class MethodVisitor {

    protected MethodVisitor mv;

    public MethodVisitor(final int api) {}
    public MethodVisitor(final int api, final MethodVisitor mv) {}

    public void visitParameter(String name, int access) {}

    public AnnotationVisitor visitAnnotationDefault() {}

    public AnnotationVisitor visitAnnotation(String desc, boolean visible) {}

    public AnnotationVisitor visitTypeAnnotation(int typeRef,
            TypePath typePath, String desc, boolean visible) {}

    public AnnotationVisitor visitParameterAnnotation(int parameter,
            String desc, boolean visible) {}

    public void visitAttribute(Attribute attr) {}

    public void visitCode() {}

    public void visitFrame(int type, int nLocal, Object[] local, int nStack,
            Object[] stack) {}

        //visitInsn、visitVarInsn、visitMethodInsn等以Insn结尾的方法可以添加方法实现的字节码
    public void visitInsn(int opcode) {}

    public void visitIntInsn(int opcode, int operand) {}

        //访问局部变量指令--局部变量指令是加载loads或存储stores局部变量的指令
   // ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE or RET.
    public void visitVarInsn(int opcode, int var) {}

    public void visitTypeInsn(int opcode, String type) {}

    public void visitFieldInsn(int opcode, String owner, String name,
            String desc) {}

    @Deprecated
    public void visitMethodInsn(int opcode, String owner, String name,
            String desc) {}

        //访问方法的指令 - 方法指令是调用方法的指令
        //要访问的类型指令的操作码。可以是INVOKEVIRTUAL,INVOKESPECIAL,INVOKESTATIC或INVOKEINTERFACE。
    public void visitMethodInsn(int opcode, String owner, String name,
            String desc, boolean itf) {}

    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
            Object... bsmArgs) {}

    public void visitJumpInsn(int opcode, Label label) {}

    public void visitLabel(Label label) {}

    public void visitLdcInsn(Object cst) {}

    public void visitIincInsn(int var, int increment) {}

    public void visitTableSwitchInsn(int min, int max, Label dflt,
            Label... labels) {}

    public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {}

    public void visitMultiANewArrayInsn(String desc, int dims) {}

    public AnnotationVisitor visitInsnAnnotation(int typeRef,
            TypePath typePath, String desc, boolean visible) {}

    public void visitTryCatchBlock(Label start, Label end, Label handler,
            String type) {}

    public AnnotationVisitor visitTryCatchAnnotation(int typeRef,
            TypePath typePath, String desc, boolean visible) {}

    public void visitLocalVariable(String name, String desc, String signature,
            Label start, Label end, int index) {}

    public AnnotationVisitor visitLocalVariableAnnotation(int typeRef,
            TypePath typePath, Label[] start, Label[] end, int[] index,
            String desc, boolean visible) {}

    public void visitLineNumber(int line, Label start) {}

    public void visitMaxs(int maxStack, int maxLocals) {}

    public void visitEnd() {}
}

Label
  • Label的作用是为了条件跳转,label必须对应一条字节码指令,通过mv.visitLabel(label) 来调用,并且visitLabel的调用必须紧跟着label对象制定的指令
  • 如label指向goto后
mv.visitJumpInsn(Opcodes.GOTO, end);

你可能感兴趣的:(class(二)使用ASM动态生成class文件)