美文网首页
16 - MethodVisitor生成构造方法

16 - MethodVisitor生成构造方法

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

先回顾下asm能做什么


asm能做什么

在当前阶段,我们关注如何生成代码

<init>()方法

在.class文件中,构造方法的名字是<init>,它表示instance initialization method的缩写。

预期目标
public class HelloWorld {
}

或者

public class HelloWorld {
    public HelloWorld() {
        super();
    }
}
编码实现
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();
        }

        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类中<init>()方法对应的Instruction内容如下:

public sample.HelloWorld();
  Code:
     0: aload_0
     1: invokespecial #9                  // Method java/lang/Object."<init>":()V
     4: return

Frame变化如下:

<init>()V
[uninitialized_this] []
[uninitialized_this] [uninitialized_this]
[sample/HelloWorld] []
[] []

在这里,我们看到一个很“不一样”的变量,就是uninitialized_this,它就是一个“引用”,它指向的内存空间还没有初始化;等经过初始化之后,uninitialized_this变量就变成this变量。

小结

通过上面的示例,我们注意四个知识点:

  • 如何使用ClassWriter类。
    1. 创建ClassWriter类的实例。
    2. 调用ClassWriter类的visitXxx()方法。
    3. 调用ClassWriter类的toByteArray()方法。
  • 在使用MethodVisitor类时,其中visitXxx()方法需要遵循的调用顺序。
    1. 调用visitCode()方法,调用一次
    2. 调用visitXxxInsn()方法,可以调用多次
    3. 调用visitMaxs()方法,调用一次
    4. 调用visitEnd()方法,调用一次
  • 在.class文件中,构造方法的名字是<init>。从Instruction的角度来讲,调用构造方法会用到invokespecial指令。
  • 从Frame的角度来讲,在构造方法<init>()中,local variables当中索引为0的位置存储的是什么呢?如果还没有进行初始化操作,就是uninitialized_this变量;如果已经进行了初始化操作,就是this变量。

相关文章

  • 16 - MethodVisitor生成构造方法

    先回顾下asm能做什么 在当前阶段,我们关注如何生成代码 ()方法 在.class文件中,构造方法的名...

  • 17 - MethodVisitor生成静态方法

    方法 在.class文件中,静态初始化方法的名字是,它表示class initia...

  • 封装

    构造方法: 无参构造方法,若没有写系统自动生成,若自己构造,则系统不再自动生成。 public classMonk...

  • 22 - ASM之Label类

    在程序中,有三种基本控制结构:顺序、选择和循环。我们现在已经知道,MethodVisitor类是用于生成方法体的代...

  • JavaScript(三)(对象/原型/继承)

    封装:将属性和方法封装进对象 构造函数:函数中有this指向对象 从构造函数生成实例: 生成实例的时候,为每个实例...

  • 2018-07-09学习小结 - 包及访问权限6

    学习 18.5 构造方法私有化——单例设计模式(Singleton) 范例 18-9 自动生成的构造方法的类 包含...

  • 231构造方法的使用

    一、为什么要使用构造方法? 对象在创建的时候需要一个构造方法,默认生成无参数构造方法,并不显示,如果需要在创建的时...

  • Java的多构造方法

    构造方法 在Java中,如果一个类没有定义构造方法,编译器会自动为我们生成一个默认构造方法,它没有参数,也没有执行...

  • 13 - ASM之MethodVisitor

    通过调用ClassVisitor类的visitMethod()方法,会返回一个MethodVisitor类型的对象...

  • JavaScript的面对对象编程3

    构造函数的缺点 JavaScript 通过构造函数生成新对象,因此构造函数可以视为对象的模板。实例对象的属性和方法...

网友评论

      本文标题:16 - MethodVisitor生成构造方法

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