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

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

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

 

题目

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个位置。




相关文章
|
28天前
主键自增
主键自增。
14 4
|
9月前
|
SQL 存储 Oracle
Oracle数据库中日期的操作、主键自增与分页查询
Oracle数据库中日期的操作、主键自增与分页查询
80 0
|
4月前
|
关系型数据库 MySQL 数据库
MySQL中列属性(主键、唯一键和自增等)使用实践
MySQL中列属性(主键、唯一键和自增等)使用实践
128 0
|
5月前
|
NoSQL Redis
redis自增减
redis自增减
25 0
|
5月前
阿里云RPA这个继续循环的组件是不是会自动自增一呢
阿里云RPA这个继续循环的组件是不是会自动自增一呢
45 1
|
6月前
|
存储 算法 安全
场景应用:id全局唯一且自增,如何实现?
场景应用:id全局唯一且自增,如何实现?
|
8月前
|
算法 NoSQL 关系型数据库
数据库主键一定要自增吗?有哪些场景不建议自增?
数据库主键一定要自增吗?有哪些场景不建议自增?
283 0
|
存储 缓存 Oracle
关于自增id 你可能还不知道
在使用MySQL建表时,我们通常会创建一个自增字段(AUTO_INCREMENT),并以此字段作为主键。本篇文章将以问答的形式讲述关于自增id的一切。 注: 本文所讲的都是基于Innodb存储引擎。
218 0
|
存储 SQL 关系型数据库
MySQL 建表为啥设置自增 id?用流水号当主键不正好么?
本文主要通过查阅资料,了解为什么要设置一个和业务无关的自增 id 用来当做主键,很多内容比较浅显,比如 InnoDB 的 B+ 树,页分裂及页合并,插入过程等都没有进行深入研究,有兴趣的小伙伴可以更深入的研究下。 同时在建表时除了要设置一个自增 id 用来当做主键,小伙伴们在业务开发过程中是否也会遇到一种情况:用户的注销,数据的删除等都是进行的逻辑删除,而不是物理删除。 本篇文章介绍比较简陋,不足之处,希望大家多多指正。
558 0
|
cobar 算法 关系型数据库
分库分表与到底要不要用自增ID?
抛开具体业务需求和场景谈论技术方案,无异于纸上谈兵。没有哪一项技术或解决方案有绝对的好坏、优劣之分。都是相对意义上的区分,否则这些项技术或方案是怎么产生的?一定也是为了解决某类具体场景的问题而产生的,在彼时彼刻都可谓 “先进”技术。
分库分表与到底要不要用自增ID?