首先:
无论 i++ 还是 ++i,这两个都不是原子操作,详情看这里 i++为什么不是原子操作
- i++ : 先取i的值作为表达式的值,然后执行 i = i + 1
- ++i : 先执行 i = i + 1,再取运算完之后的值作为表达式的值
举例和解释:
先来个热身的简单例子
public static void main(String[] args) {
int i = 0;
System.out.println("i++的值为:" + i++);
i = 0;
System.out.println("++i的值为:" + ++i);
}
输出:(有图有真相)
可以看到表达式的值为先前说的那样,可以总结为:
- 加号在前,先加再取值
- 加号在后,先取值再加
接下来举一个常见的面试题例子:
public static void main(String[] args) {
int i = 0;
i = i ++;
System.out.println("i的值为:" + i);
}
结果:
可以看到 i = i ++;的结果为0。
看到这里可能有的小伙伴会奇怪,i = i ++ 为什么结果为0而不是1,这不是先让 i = 0,然后让 i自增么,怎么就不对了呢?
其实前面说的没有问题,这里有两个运算符 第一个是赋值运算符 ' = ' , 第二个是 自增运算符 ' ++ ' , 我们知道赋值运算符的顺序为先计算表达式右边,再把表达式的值赋值给左边,真正的运算顺序是先计算 i ++,在计算 赋值给i,而从上一个例子我们可以知道表达式 i ++ 的值为 0,此时,=右边表达式的值为0,接下来是i 的自增操作,这个操作完毕后 i 的值确实为1,但还有下一步:把表达式的值赋值给 i ,表达式的值为0,于是 i 的值又变为了 0 ,最后输出 i 的值为 0。
下面我们来看这段代码的底层是怎么实现的(这部分适合对java有一定了解的童鞋看):
(为了简单,把输出部分的代码取掉了已经)
下面我来添加点注释
public static void main(java.lang.String[]);
Code:
0: iconst_0 //第一步先把常量 0 放入栈顶
1: istore_1 //从栈顶取出值(0)赋值给变量1( 前两行对应 int i = 0;)
2: iload_1 //把变量1的值取出放入栈顶(这一步是取 i++ 的值作为整个表达式的值)
3: iinc 1, 1 //让变量1的值加1 (这一步对应 ++ 自增运算符)
6: istore_1 //把栈顶的值取出,赋值给变量1 ( 对应 = 赋值运算符)
7: return //main方法结束
代码前两行(标号为 0,1的行)是对应的 int i = 0;
(int i = 0;其实是int i; 然后 i = 0;其中变量声明的部分是储存在局部变量表中,方法字节码中没有 int i; 声明的部分)
即把常数0赋值给 i, (这里i 就是 变量 1),i = 0;也分两步其实,第一步先把0放入栈顶,然后从栈顶取出值放入变量1
标号为 2 3 6 的行对应 i = i ++;(不要问第4行第5行去哪里了,我们知道 i ++ 并不是一个原子操作,而是先取 i 的值,然后 让这个值+1, 然后把这个值写回 i ,关于原子操作不懂的同学百度一下~。这里java的字节码为后两行空出来了)。
2:先计算 = 右边 i++ 的值,发现该值为 i ,就把 i 的值(此时为0)放入栈顶
3:计算 i ++的值,现在 i 的值为1(这里还可以展开,想继续深入了解的同学到这:深入理解i++为什么不是原子操作)
6:标号为2的代码已经计算出 = 赋值运算符右边的值了,直接把栈顶的值写会 = 左边的 i
7:代码结束,return
因此 i = i ++ 操作相当于没有执行任何操作。
欢迎点评和指正,点击这里查看博主的其他博客