美文网首页
17 - MethodVisitor生成静态方法

17 - MethodVisitor生成静态方法

作者: 舍是境界 | 来源:发表于2022-01-27 07:59 被阅读0次

    <clinit>方法

    在.class文件中,静态初始化方法的名字是<clinit>,它表示class initialization method的缩写。

    目标
    public class HelloWorld {
        static {
            System.out.println("class initialization method");
        }
    }
    
    编码实现
    import lsieun.utils.FileUtils;
    import org.objectweb.asm.ClassWriter;
    import org.objectweb.asm.MethodVisitor;
    
    import static org.objectweb.asm.Opcodes.*;
    
    public class HelloWorldGenerateCore {
        public static void main(String[] args) throws Exception {
            String relative_path = "sample/HelloWorld.class";
            String filepath = FileUtils.getFilePath(relative_path);
    
            // (1) 生成byte[]内容
            byte[] bytes = dump();
    
            // (2) 保存byte[]到文件
            FileUtils.writeBytes(filepath, bytes);
        }
    
        public static byte[] dump() throws Exception {
            // (1) 创建ClassWriter对象
            ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
    
            // (2) 调用visitXxx()方法
            cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, "sample/HelloWorld", null, "java/lang/Object", null);
    
            {
                MethodVisitor mv1 = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
                mv1.visitCode();
                mv1.visitVarInsn(ALOAD, 0);
                mv1.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
                mv1.visitInsn(RETURN);
                mv1.visitMaxs(1, 1);
                mv1.visitEnd();
            }
    
            {
                MethodVisitor mv2 = cw.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
                mv2.visitCode();
                mv2.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
                mv2.visitLdcInsn("class initialization method");
                mv2.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
                mv2.visitInsn(RETURN);
                mv2.visitMaxs(2, 0);
                mv2.visitEnd();
            }
    
            cw.visitEnd();
    
            // (3) 调用toByteArray()方法
            return cw.toByteArray();
        }
    }
    
    验证结果
    public class HelloWorldRun {
        public static void main(String[] args) throws Exception {
            Class<?> clazz = Class.forName("sample.HelloWorld");
            System.out.println(clazz);
        }
    }
    
    Frame的变化

    对于HelloWorld类中<clinit>()方法对应的Instruction内容如下:

    static {};
      Code:
         0: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
         3: ldc           #20                 // String class initialization method
         5: invokevirtual #26                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
         8: return
    

    该方法对应的Frame变化情况如下:

    <clinit>()V
    [] []
    [] [java/io/PrintStream]
    [] [java/io/PrintStream, java/lang/String]
    [] []
    [] []
    

    小结

    1. 在使用MethodVisitor类时,其中visitXxx()方法需要遵循的调用顺序。
    2. 在.class文件中,静态初始化方法的名字是<clinit>,它的方法描述符是()V。

    相关文章

      网友评论

          本文标题:17 - MethodVisitor生成静态方法

          本文链接:https://www.haomeiwen.com/subject/rhblhrtx.html