zoukankan      html  css  js  c++  java
  • 一个方法的本地变量表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

      

  • 相关阅读:
    触发器心得
    心得:上下游企业的各自特点和出路
    MySQL 触发器例子(两张表同步增加和删除)
    JQuery动态隐藏和显示DIV
    MySQL 触发器例子(下订单自动减少库存)
    Step By Step(Lua目录)
    客户端服务端
    C#多线程1
    GFS架构分析
    一个简单的Windows Socket可复用框架
  • 原文地址:https://www.cnblogs.com/juniorMa/p/13468521.html
Copyright © 2011-2022 走看看