小程序容器助力企业在金融与物联网领域实现高效合规运营,带来的新机遇与挑战如何管理?
665
2022-12-10
浅谈JVM 底层解析 i++和 ++i 区别
目录一、前言二、代码实现三、字节码指令四、字节码解析1. 第一类问题2. 第二类问题3. 第三类问题4. 第四类问题
一、前言
如果只用普通的知识解释i++和++i的话
i++ 先将i赋值再++
++i 先++再赋值
但是这简单的回答并不能入吸引面试官的眼球,如果用java字节码指令分析则效果完全不同
二、代码实现
public class OperandStackTest {
/**
程序员面试过程中, 常见的i++和++i 的区别
*/
public static void add(){
//第1类问题:
int i1 = 10;
i1++;
System.out.println("i1 =" + i1);//11
int i2 = 10;
++i2;
System.out.println("i2 =" + i2);//11
//第2类问题:
int i3 = 10;
int i4 = i3++;
System.out.println("i3 =" + i3);//11
System.out.println("i4 =" + i4);//10
int i5 = 10;
int i6 = ++i5;
System.out.println("i5 =" + i5);//11
System.out.println("i6 =" + i6);//11
//第3类问题:
int i7 = 10;
i7 = i7++;
System.out.println("i7 =" + i7);//10
int i8 = 10;
i8 = ++i8;
System.out.println("i8 =" + i8);//11
//第4类问题:
int i9 = 10;
int i10 = i9++ + ++i9;//10+12
System.out.println("i9 =" + i9);//12
System.out.println("i10 =" + i10);//22
}
public static void main(String[] args) {
add();
}
}
运行结果
i1 = 11
i2 = 11
i3 = 11
i4 = 10
i5 = 11
i6 = 11
i7 = 10
i8 = 11
i9 = 12
i10 = 22
三、字节码指令
通过javap -v out目录下的class文件名 在终端运行得到如下结果
public static void add();
descriptor: ()V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=10, args_size=0
0: bipush 10
2: istore_0
3: iinc 0, 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: bipush 10
15: istore_1
16: iinc 1, 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: bipush 10
28: istore_2
29: iload_2
30: iinc 2, 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: bipush 10
50: istore 4
52: iinc 4, 1
55: iload 4
57: istore 5
59: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
62: iload 4
64: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
67: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
70: iload 5
72: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
75: bipush 10
77: istore 6
79: iload 6
81: iinc 6, 1
84: istore 6
86: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
89: iload 6
91: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
94: bipush 10
96: istore 7
98: iinc 7, 1
101: iload 7
103: istore 7
105: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
108: iload 7
110: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
113: bipush 10
115: istore 8
117: iload 8
119: iinc 8, 1
122: iinc 8, 1
125: iload 8
127: iadd
128: istore 9
130: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
133: iload 8
135: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
138: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
141: iload 9
143: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
146: return
四、字节码解析
1. 第一类问题
//第1类问题:
int i1 = 10;
i1++;
System.out.println("i1 =" + i1);//11
int i2 = 10;
++i2;
System.out.println("i2 =" + i2);//11
对应字节码指令为
0: bipush 10
2: istore_0
3: iinc 0, 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: bipush 10
15: istore_1
16: iinc 1, 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
先将i1的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表0的位置,然后执行iinc将0位置的值+1,然后将局部变量表0位置的数入栈执行输出操作
所以i1的值为11
先将i2的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表1的位置,然后执行iinc将1位置的值+1,然后将局部变量表1位置的数入栈执行输出操作
所以i2的值为11
由于没有赋值操作,区别不大
2. 第二类问题
//第2类问题:
int i3 = 10;
int i4 = i3++;
System.out.println("i3 =" + i3);//11
System.out.println("i4 =" + i4);//10
int i5 = 10;
int i6 = ++i5;
System.out.println("i5 =" + i5);//11
System.out.println("i6 =" + i6);//11
对应字节码为
26: bipush 10
28: istore_2
29: iload_2
30: iinc 2, 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: bipush 10
50: istore 4
52: iinc 4, 1
55: iload 4
57: istore 5
59: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
62: iload 4
64: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
67: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
70: iload 5
72: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
先将i3入栈存储到局部变量表2的位置,然后将它入栈,执行iinc将2位置的值加一,i4存储到局部表量表3的位置
所以i3是11,i4还是10
将i5入栈存储到局部变量表4的位置,由于是++i所以先iinc将4位置的值加一,然后将局部变量表4的值入栈,执行赋值操作
所以i5、i6都是11
3. 第三类问题
//第3类问题:
int i7 = 10;
i7 = i7++;
System.out.println("i7 =" + i7);//10
int i8 = 10;
i8 = ++i8;
System.out.println("i8 =" + i8);//11
对应字节码
75: bipush 10
77: istore 6
79: iload 6
81: iinc 6, 1
84: istore 6
86: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
89: iload 6
91: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
94: bipush 10
96: istore 7
98: iinc 7, 1
101: iload 7
103: istore 7
105: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
108: iload 7
110: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
先将i7入栈,然后存到局部变量表6的位置,先把i6入栈,然后把6处的值加一,由于又将这个值存储到局部变量表6处,所以产生覆盖又把值变为10
所以i7为10
而++i不会产生覆盖先执行加一然后再把值入栈,在赋值给局部变量表中
所以i8为11
4. 第四类问题
//第4类问题:
int i9 = 10;
int i10 = i9++ + ++i9;//10+12
System.out.println("i9 =" + i9);//12
System.out.println("i10 =" + i10);//22
对应字节码为
113: bipush 10
115: istore 8
117: iload 8
119: iinc 8, 1
122: iinc 8, 1
125: iload 8
127: iadd
128: istore 9
130: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
133: iload 8
135: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
138: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
141: iload 9
143: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
146: return
先将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处的值入栈执行输出语句
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~