美文网首页
从字节码层面去看new一个对象的执行过程

从字节码层面去看new一个对象的执行过程

作者: Wannay | 来源:发表于2021-11-05 18:00 被阅读0次

    我们一般使用如下这样的方式去创建一个对象:StringBuffer buffer = new StringBuffer();

    它对应的字节码应该包括如下这些部分,算是对这个对象的创建和使用过程。

             0: new           #2                  // class java/lang/StringBuffer
             3: dup
             4: invokespecial #3                  // Method java/lang/StringBuffer."<init>":()V
             7: astore_1
             8: aload_1
    

    先是使用new字节码,并通过#2去常量池找到class java/lang/StringBuffer这样一个Class,从而去创建一个StringBuffer对象,但是这里仅仅是创建对象罢了,还是个空壳的对象,连构造器方法都没执行那种。

    真正的构造器方法还是在invokespecial字节码中去执行的,我们可以看到它是通过#3去常量池里去找到Method java/lang/StringBuffer."<init>":()V这样一个方法并进行执行。

    为什么newinvokespecial之间还有一个dup指令的存在呢?首先我们得知道dup是什么意思?它其实是duplicate的缩写,也就是重复的意思,也就是把刚刚创建出来的对象的引用,在栈里面再拷贝一份。

    至于为什么要dup一遍?我们首先要知道invokespecial指令是会消耗掉刚刚new出来的对象的在操作数栈中的引用的。如果直接消耗掉了,那么我们后续怎么拿到这个对象的引用?很显然拿不到对吧,因此就得dup一遍,这样就算栈中消耗了一份,也还会剩下来一份,后续才可以拿到该对象引用。

    接着就是astore_1指令,它的作用就是将栈顶的元素(就是我们刚刚dup拷贝的对象引用),保存到局部变量表的1号槽位(slot 1)中,保存的同时也会将栈顶的元素消耗掉,因此后续得通过aload_1从局部变量表中拿到对象的引用。

    我们可以查看局部变量表

          LocalVariableTable:
            Start  Length  Slot  Name   Signature
                0      16     0  args   [Ljava/lang/String;
                8       8     1 buffer   Ljava/lang/StringBuffer;
    

    我们可以发现在局部变量表的1号槽位确实放了一个buffer的引用,而且甚至局部变量表中也还保存了引用的名称。

    相关文章

      网友评论

          本文标题:从字节码层面去看new一个对象的执行过程

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