经常出错的一道题
public class AddTest {
public static void main(String[] args) {
int i = 0;
i = i++;
System.out.println("i=" + i);
}
}
输出结果是多少呢?自己思考后继续往下看效果更好哦
=================分界线=================
正确答案是 0
如果能完全想明白,可以结束往下阅读了。如果有疑惑,请继续读下去
我刚看到这道题,给的答案也是 1,因为我以往的理解是 i++ 是先赋值,然后再进行 ++ 操作,在赋值时,i 确实为 0,但 i 应该完成了自增操作,输出的 i 应该为 1 呀,自己也验证了一下,的确是 0。想不明白那就看看字节码吧,也许从中能找到答案
先通过 javac AddTest.java 生成 AddTest.class 文件,然后通过 javap -v AddTest.class 查看具体的字节码(只截取了部分)
i++字节码
首先说明左边的数字序号表示字节码的偏移量(偏移量和前面的字节码长度有关),即当前字节码所在的位置,很像行号,但不是行号
下面我们用图解的方式分析下主要步骤
i++字节码图解
通过图解我们发现操作数栈中的 0 把局部变量表 1 位置的 1 覆盖了,所以最后输出的结果是 0
指令说明
xconst_n (x为 i 表示整数,l 表示长整数,f 表示浮点数,d 表示双精度浮点数,a 表示对象引用;n 为 0~5):常量入栈指令,代表将 n 压入栈
xload_n(x 取值和 const 一样,n 为 0~3):局部变量压栈指令,将第n个局部变量压入操作数栈
xstore_n(x 取值和 const一样,n 为 0~3):出栈装入局部变量表指令,从操作数栈中弹出,赋值给局部变量 n
iinc arg1,arg2:对给定的局部变量做自增操作。执行过程中不需要修改操作数栈。接收两个操作数,第一个为局部变量表的位置,第二个为累加数
++i 呢?
说完了 i++ 就不能落下它的好兄弟 ++i
public class Add2Test {
public static void main(String[] args) {
int i = 0;
i = ++i;
System.out.println("i=" + i);
}
}
这个结果我想大家都能答对,输出 1,但是我还是想把 ++i 的字节码打出来,然后和 i++ 的进行对比
++i字节码
字节码图解如下所示
++i字节码图解
i++ 与 ++i 对比
我们把这两个图放在一起对比看下
对比
反思
为何一道简单的 i++ 的输出问题,我都能弄错?追根是因为对字节码底层的不了解,虽然我们通过字节码和画图分析出了原因,但这并不够,最好做到看到代码,对应的字节码就映射到脑中。说实话,对我来说挺难的。需要不断练习。懂了字节码会对 Java 中更多底层的知识不止知其然,更知其所以然。
上一篇: 详解MySQL 联合查询优化机制
下一篇: 萌新的nginx学习
推荐阅读
-
每天一道算法题(2020.06.18)- 电话号码的字母组合
-
从一道题看js的拆箱操作
-
JavaScript面试题:一道关于变量提升的题
-
一道简单的字符题
-
一道有意思的思维题 --- 排序、枚举
-
一道js代码填空题的解 window.alert = function(){};____;alert(1);
-
史上最强的一道化学题
-
【每日一道算法题】Leetcode之longest-increasing-path-in-a-matrix矩阵中的最长递增路径问题 Java dfs+记忆化
-
LeetCode的一道题引申的python实现的对字符串进行分词,提取词频的方法
-
一道简单的LeetCode题的优化,从优于14%到99%