一个方法的本地变量表this是何时被赋值的

这个插件是jclasslib

对于一个实例方法来说,本地变量表的0项一定是this。比如:

 

init方法和func方法的本地变量表。

那么this是什么时候被赋值的呢?

 2020-10-30记录,当时自己这么写还是很准的,因为对于static方法本地变量表的第0项还真不是this

我们看一下new一个对象的字节码,java源代码如下

public class AppTest {

    private int i ;
    private String s = "aaa";
    private static String cons = "bbb";
    public AppTest(int p) {
        this.i = p;
    }

    public static String process(Integer i, Long l, String s) {
        int j = 6;
        int k = 4;
        int result = j + k;
        Long n = 5l;
        String t = "m";
        return "1";
    }

    public void func(int input) {
        i = input;
    }

    public void func2(int input) {
        i = input;
    }
    public static void main(String[] args) {
//        process(1,2L,"ss");
        AppTest test = new AppTest(22);
        Integer i = 90;
    }
}

 

 0 new #10 <com/suning/mxz/AppTest>
 3 dup
 4 bipush 22
 6 invokespecial #11 <com/suning/mxz/AppTest.<init>>
 9 astore_1
10 bipush 90
12 invokestatic #12 <java/lang/Integer.valueOf>
15 astore_2
16 return

  注意 

invokespecial #11 <com/suning/mxz/AppTest.<init>> 我们解释一下invokespecial这个字节码指令

格式

invokespecial
indexbyte1
indexbyte2

编码

invokespecial = 183 (0xb7)

操作数栈

..., objectref, [arg1, [arg2 ...]] 

也就是说

invokespecial ,至少有一个入参,是一个引用类型指向当前的对象
 0 new #10 <com/suning/mxz/AppTest> 分配空间,并把得到的地址压入操作数栈
 3 dup                              把操作数栈栈顶拷贝一份,也就是现在的操作数栈有一个指向对象的指针了
 4 bipush 22                        把22压入操作数栈
  紧接着就是调用
  invokespecial #11 <com/suning/mxz/AppTest.<init>> 所以栈顶的两个操作数就弹出来了,作为invokespecial的入参

    如果该方法不是native的,nargs个参数和objectref从栈中弹出,在当前JVM栈中为该方法创建一个新的栈帧。
  Objectref和nargs个参数值连续存入新栈帧的局部变量表。
  Objectref存入slot0,arg1存入slot1(或者,如果arg1为long或double类型,则占连续两个slot,为slot1,slot2),以此类推。
  任何float类型的变量在存入局部变量表之前都会先进行值集转换。新栈帧成为当前栈帧,JVM PC设置为新方法的第一条指令,程序执行从该方法第一条指令继续。

  也就是this的引用就是在调用 invokespecial 被赋值的

   继续分析下该例子中其他的字节码指令

  第9行的 astore_1

  从oracle 官网上看

  Store reference into local variable 就是把一个引用对象赋值给本地变量表1号变量

   1号变量就是test 正好对应这句代码

  

AppTest test = new AppTest(22);

  astore 和 istore都是 复制操作,区别就是a表示的是引用类型,i表示整型

  我们不妨再看看构造方法的字节码

  

public class AppTest {

    private int i = 55;
    private String s = "aaa";
    private static String cons = "bbb";

    public AppTest() {
        this.i = 66;
    }
0 aload_0
 1 invokespecial #1 <java/lang/Object.<init>> 先执行Object的init
 4 aload_0
 5 bipush 55
 7 putfield #2 <com/suning/mxz/AppTest.i>
10 aload_0
11 ldc #3 <aaa>
13 putfield #4 <com/suning/mxz/AppTest.s> 把成员变量i s都赋了值
16 aload_0
17 bipush 66
19 putfield #2 <com/suning/mxz/AppTest.i> 这里才是
public AppTest() {
        this.i = 66;
    }
22 return

  

aload_0
The <n> must be an index into the local variable array of the current frame (§2.6).
The local variable at <n> must contain a reference.
The objectref in the local variable at <n> is pushed onto the operand stack.
把本地变量表的0号取出并压入操作数栈,0号就是this

 

  

posted on 2020-08-10 10:53  MaXianZhe  阅读(522)  评论(0编辑  收藏  举报

导航