关于++i 和 i++ 的一道面试题

直接看题目:

 public void autoIncre() {
        int i = 1;
        i = i++;
        int j = i++;
        int k = i + ++i*i++;
        System.out.println(i);
        System.out.println(j);
        System.out.println(k);
}

这道题的结果为:

i = 4

j = 1

k = 11

首先要知道:

  • = 的右边从左到右加载值,依次压入操作数栈中
  • 自增、自减操作都是在局部变量表中直接修改变量的值,不经过操作数栈
  • 在最后的赋值之前,临时结果是存储在操作数栈中,最后赋值才是存储在局部变量表中

不知道没关系,可以先记住,方便对后面图解过程的理解

接下来通过字节码对代码逐行分析:

第一行代码:
 int i = 1;
 
 对应的字节码:
 ICONST_1           //I-int Const-常量
 ISTORE 1           //store-存储,即存储一个int类型的常量 
第二行代码:
 i=i++;

 对应的字节码:
 ILOAD 1            //压入操作数栈
 IINC 1 1           //自增1
 ISTORE 1           //存储到局部变量表中

图解:
在这里插入图片描述
通过上面可以看到,本来局部变量表中的 i 已经完成了自增,但是在进行赋值时,操作数栈中的数据弹出,存储到局部变量表中,但是操作数栈的数据并没有经过计算,所以每次自增的结果都被覆盖了。最终结果还是1。

第三行代码:
j = i++;
 
 对应的字节码:
 ILOAD 1            //压入操作数栈
 IINC 1 1           //自增1
 ISTORE 2           //存储到局部变量表中,这里的2指的是第二个变量

图解:
在这里插入图片描述
这行代码与第一行代码字节码步骤是比较相似的,只是在存储时,操作数栈弹出的数存储到局部变量表的 j 中,

而 i 的值没有被覆盖,为2。

第四行代码:
 k = i + ++i*i++;  
 
 对应的字节码:
 ILOAD 1     //压入i
 IINC 1 1    //执行自增
 ILOAD 1     //压入i
 ILOAD 1     //压入i
 IINC 1 1    //执行自增
 IMUL        //乘
 IADD        //加
 ISTORE 3    //存储

这一行会比较复杂,我们给捋一下。由最前面说到的,= 的右边的从左到右加载值,依次压入操作数栈中,所以结合字节码,可以得到下图:
在这里插入图片描述

图解:(蓝色表示该步骤变化的地方)
在这里插入图片描述在这里插入图片描述

注意:这里的步骤六相乘得到的临时结果不会存储到 k 中,而是仍然在操作数栈中
在这里插入图片描述在这里插入图片描述

总结:

  • = 的右边从左到右加载值,依次压入操作数栈中
  • 自增、自减操作在局部变量表中直接修改变量的值,不经过操作数栈
  • 在最后的赋值之前,临时结果是存储在操作数栈中,最后赋值才是存储在局部变量表中
参考链接:

https://blog.csdn.net/qq_41907991/article/details/105337049

https://blog.csdn.net/android_cai_niao/article/details/106027313

猜你喜欢

转载自blog.csdn.net/weixin_44707004/article/details/107548935