浅谈JVM 底层解析 i++和 ++i 区别

网友投稿 665 2022-12-10

浅谈JVM 底层解析 i++和 ++i 区别

浅谈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小时内删除侵权内容。

上一篇:springboot @Value实现获取计算机中绝对路径文件的内容
下一篇:SpringBoot yaml中的数组类型取值方式
相关文章

 发表评论

暂时没有评论,来抢沙发吧~