越努力,越幸运

微信公众号:JoonWhee。专注于Java原创知识交流,优秀技术文章、职场人生、面试经验分享。...

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

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


题目


我相信有不少人会认为输出是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个位置。



阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。微信公众号:JoonWhee,欢迎关注。 https://blog.csdn.net/v123411739/article/details/79762215
个人分类: 面试精选
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

不良信息举报

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

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭