关于自增操作,你真的懂了吗?

微信搜索【程序员囧辉】,关注这个坚持分享技术干货的程序员。

最近看见一道有意思的面试题,是关于自增操作的,让我回想起以前自己也遇到过,并且曾经也让我困惑过,今天拿出来跟大家分享,希望对大家有帮助。

 

题目

我相信有不少人会认为输出是100,但实际运行输出是0。为什么了?要知道其中的原理,我们需要先了解下栈中的局部变量表(本地变量表)和操作数栈。

 

局部变量表和操作数栈

在介绍JoonWhee:Java虚拟机:Java内存区域的Java虚拟机栈时,我们说过“每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息”。局部变量表很容易知道就是用来存储方法中的局部变量,而操作数栈则是用来进行各种运算。

 

解惑

该题目中循环自增部分对应的字节码如下。

图中三个红圈的字节码从上到下分别对应:“j = 0”、“i = 0”、“j = j++”。可以看到“j = j++”共执行了3个步骤:

  1. 将第1个本地变量推送至栈顶,即将 j 推送至栈顶,此时 j = 0。
  2. 将第1个本地变量递增1,此时本地变量表里的 j = 0,递增完后 j = 1。
  3. 将栈顶数值存入第1个本地变量,此时栈顶的 j = 0,而本地变量的 j = 1,将栈顶的数值存入本地变量,则本地变量的 j 值被覆盖,变为 j = 0。

看完以上3个步骤,相信你已经知道了,为什么这个题目的输出是0了。

上图红圈对应的7行字节码执行过程,如下图所示,从左往右,每一列对应1行字节码。

 

扩展

 

如果我们把上文的“j = j++”改成“j = ++j”、“j++”、“++j”会有什么样的变化了。

案例1:改成“j = ++j”后,字节码如下:

可以看到“j = ++j”也是执行了3个步骤:

  1. 将第1个本地变量递增1,此时本地变量表里的 j = 0,递增完后 j = 1。
  2. 将第1个本地变量推送至栈顶,即将 j 推送至栈顶,此时 j = 1。
  3. 将栈顶数值存入第1个本地变量,此时栈顶的 j = 1,本地变量的 j = 1,将栈顶的数值存入本地变量,则本地变量的 j 值被覆盖,还是 j = 1。

因此,如果将题目中的自增操作换成“j = ++j”,输出结果为100。

 

 

案例2:改成“++j”后,字节码如下:

可以看到“++j”只执行了一个步骤,就是将第1个本地变量递增1,此时本地变量表里的 j = 0,递增完后 j = 1。

 

案例3:改成“j++”后,字节码如下:

 

可以看到“j++”只执行了一个步骤,就是将第1个本地变量递增1,此时本地变量表里的 j = 0,递增完后 j = 1。

 

 

看完几个案例后,我们知道了,造成“j = j++”的结果为0的原因是:先将 j 的值放到了操作数栈,然后对本地变量表里的 j 进行递增1,最后将操作数栈的旧值覆盖掉本地变量表里的新值,导致 j = 0。

 

相关字节码

最后介绍下文章用到的几个字节码。

其中字节码开头的 i 代表int,中间的store、inc、load代表一个操作,结尾的数字则代表具体数值或位置的下标,例如0代表第1个位置。

 

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员囧辉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值