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

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

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

 

题目

image.png

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

 

局部变量表和操作数栈


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

 

解惑


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

image.png

图中三个红圈的字节码从上到下分别对应:“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行字节码。

image.png


扩展


 

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


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

image.png

可以看到“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”后,字节码如下:

image.png

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

 

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

image.png


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

 

 

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

 

相关字节码


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

image.png

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




相关文章
|
8月前
主键自增
主键自增。
42 4
|
29天前
|
存储 关系型数据库 MySQL
InnoDB为什么使用自增id作为主键?
MySQL以数据页(默认16K)为单位存储数据。自增ID主键时,写满一页直接申请新页;非自增ID主键需保持索引有序,插入数据可能引发页分裂,即需将部分数据移至新页,影响插入效率。
40 6
|
8月前
|
缓存 算法 安全
被追着问UUID和自增ID做主键哪个好,为什么?
讨论了UUID和自增ID作为数据库主键的优缺点。UUID全局唯一,适合分布式系统,但存储空间大,不适合范围查询。自增ID存储空间节省,查询效率高,但分库分表困难,可预测性高。UUID版本包括基于时间戳(V1)、随机数(V4)以及基于名称空间的MD5(V3)和SHA1(V5)散列。
被追着问UUID和自增ID做主键哪个好,为什么?
|
7月前
|
关系型数据库 数据库
Postgres使用序列实现主键自增基于navcat操作
Postgres使用序列实现主键自增基于navcat操作
114 0
|
8月前
|
存储 关系型数据库 MySQL
在MySQL中, 自增主键和UUID作为主键有什么区别?
自增主键和UUID在MySQL中各有优缺点,选择哪种方式作为主键取决于具体的应用场景和需求。例如,在需要高性能插入和查询的场景下,自增主键可能更合适;而在需要保证主键全局唯一性和不可预测性的场景下,UUID可能更合适。
104 0
|
8月前
|
存储 关系型数据库 MySQL
MySQL中, 自增主键和UUID作为主键有什么区别?
MySQL中, 自增主键和UUID作为主键有什么区别?
94 0
|
关系型数据库 MySQL 数据库
MySQL中列属性(主键、唯一键和自增等)使用实践
MySQL中列属性(主键、唯一键和自增等)使用实践
273 0
|
算法 NoSQL 关系型数据库
数据库主键一定要自增吗?有哪些场景不建议自增?
数据库主键一定要自增吗?有哪些场景不建议自增?
482 0
|
存储 关系型数据库 MySQL
InnoDB为什么使用自增id作为主键
InnoDB是MySQL数据库中一种常用的存储引擎,它使用自增id作为主键的设计是出于多方面的考虑。
467 0