从 JVM 层面理解 i++ 和 ++i 的真正区别!
前言
如果只用普通的知识解释i++和++i的话
- i++ 先将i赋值再++
- ++i 先++再赋值
代码实现
public class OperandStackTest {
/**
程序员面试过程中, 常见的i++和++i 的区别
*/
public static void add(){
//第1类问题:
int i1 = 10;
i1++;
System.out.println(i1);
//11int i2 = 10;
++i2;
System.out.println(i2);
//11//第2类问题:
int i3 = 10;
int i4 = i3++;
System.out.println(i3);
//11
System.out.println(i4);
//10int i5 = 10;
int i6 = ++i5;
System.out.println(i5);
//11
System.out.println(i6);
//11//第3类问题:
int i7 = 10;
i7 = i7++;
System.out.println(i7);
//10int i8 = 10;
i8 = ++i8;
System.out.println(i8);
//11//第4类问题:
int i9 = 10;
int i10 = i9++ + ++i9;
//10+12
System.out.println(i9);
//12
System.out.println(i10);
//22
}public static void main(String[] args) {
add();
}
}
运行结果
文章图片
字节码指令 通过
javap -v out
目录下的class文件名 在终端运行得到如下结果 public static void add();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=10, args_size=0
0: bipush10
2: istore_0
3: iinc0, 1
6: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
9: iload_0
10: invokevirtual #5// Method java/io/PrintStream.println:(I)V
13: bipush10
15: istore_1
16: iinc1, 1
19: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
22: iload_1
23: invokevirtual #5// Method java/io/PrintStream.println:(I)V
26: bipush10
28: istore_2
29: iload_2
30: iinc2, 1
33: istore_3
34: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
37: iload_2
38: invokevirtual #5// Method java/io/PrintStream.println:(I)V
41: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
44: iload_3
45: invokevirtual #5// Method java/io/PrintStream.println:(I)V
48: bipush10
50: istore4
52: iinc4, 1
55: iload4
57: istore5
59: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
62: iload4
64: invokevirtual #5// Method java/io/PrintStream.println:(I)V
67: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
70: iload5
72: invokevirtual #5// Method java/io/PrintStream.println:(I)V
75: bipush10
77: istore6
79: iload6
81: iinc6, 1
84: istore6
86: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
89: iload6
91: invokevirtual #5// Method java/io/PrintStream.println:(I)V
94: bipush10
96: istore7
98: iinc7, 1
101: iload7
103: istore7
105: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
108: iload7
110: invokevirtual #5// Method java/io/PrintStream.println:(I)V
113: bipush10
115: istore8
117: iload8
119: iinc8, 1
122: iinc8, 1
125: iload8
127: iadd
128: istore9
130: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
133: iload8
135: invokevirtual #5// Method java/io/PrintStream.println:(I)V
138: getstatic#4// Field java/lang/System.out:Ljava/io/PrintStream;
141: iload9
143: invokevirtual #5// Method java/io/PrintStream.println:(I)V
146: return
解释以上运行结果 第一类问题
文章图片
对应的指令为
文章图片
先将i1的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表0的位置,然后执行iinc将0位置的值+1,然后将局部变量表0位置的数入栈执行输出操作
所以i1的值为11先将i2的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表1的位置,然后执行iinc将1位置的值+1,然后将局部变量表1位置的数入栈执行输出操作
所以i2的值为11总结 由于没有赋值操作,区别不大。
第二类问题
【从 JVM 层面理解 i++ 和 ++i 的真正区别!】
文章图片
文章图片
先将i3入栈存储到局部变量表2的位置,然后将它入栈,执行iinc将2位置的值加一,i4存储到局部表量表3的位置
所以i3是11,i4还是10将i5入栈存储到局部变量表4的位置,由于是++i所以先iinc将4位置的值加一,然后将局部变量表4的值入栈,执行赋值操作,所以都是11
第三类问题
文章图片
文章图片
先将i7入栈,然后存到局部变量表6的位置,先把i6入栈,然后把6处的值加一,由于又将这个值存储到局部变量表6处,所以产生覆盖又把值变为10。
而++i不会产生覆盖先执行加一然后再把值入栈,在赋值给局部变量表中,所以i8为11。
第四类问题
文章图片
文章图片
先将i9=10入栈,然后存在局部变量表8的位置
int i10 = i9++ + ++i9;
先iload将8位置的i9入栈然后执行iinc将8处的i9加一,然后执行++i9,在将8处的i9加一
此时i9=10+1+1为12,然后将8位置的i9入栈,执行add将栈中的两i9相加,得到的值存储到局部变量表9的位置
所以i10=10+12(i9++后还是10,++i9后是12,因为执行了两次iinc操作)
然后调用虚方法和静态方法,在将9处的值入栈执行输出语句
原文链接:https://blog.csdn.net/demo_yo...
版权声明:本文为CSDN博主「默默无闻代码人」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
近期热文推荐:
1.1,000+ 道 Java面试题及答案整理(2021最新版)
2.别在再满屏的 if/ else 了,试试策略模式,真香!!
3.卧槽!Java 中的 xx ≠ null 是什么新语法?
4.Spring Boot 2.5 重磅发布,黑暗模式太炸了!
5.《Java开发手册(嵩山版)》最新发布,速速下载!
觉得不错,别忘了随手点赞+转发哦!
推荐阅读
- Docker应用:容器间通信与Mariadb数据库主从复制
- 一个人的碎碎念
- 我从来不做坏事
- 从蓦然回首到花开在眼前,都是为了更好的明天。
- 西湖游
- 改变自己,先从自我反思开始
- leetcode|leetcode 92. 反转链表 II
- 从我的第一张健身卡谈传统健身房
- 自媒体形势分析
- 操作系统|[译]从内部了解现代浏览器(1)