好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

一、前言

如果只用普通的知识解释i++和++i的话
i++ 先将i赋值再++
++i 先++再赋值
但是这简单的回答并不能入吸引面试官的眼球,如果用java字节码指令分析则效果完全不同

二、代码实现

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

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();

     }

}

运行结果

?

1

2

3

4

5

6

7

8

9

10

i1 = 11

i2 = 11

i3 = 11

i4 = 10

i5 = 11

i6 = 11

i7 = 10

i8 = 11

i9 = 12

i10 = 22

三、字节码指令

通过javap -v out目录下的class文件名 在终端运行得到如下结果

 

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

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

2

3

4

5

6

7

8

//第1类问题:

int i1 = 10 ;

i1++;

System.out.println( "i1 =" + i1); //11

 

int i2 = 10 ;

++i2;

System.out.println( "i2 =" + i2); //11

对应字节码指令为

?

1

2

3

4

5

6

7

8

9

10

11

12

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. 第二类问题

?

1

2

3

4

5

6

7

8

9

10

//第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

对应字节码为

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

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. 第三类问题

?

1

2

3

4

5

6

7

//第3类问题:

int i7 = 10 ;

i7 = i7++;

System.out.println( "i7 =" + i7); //10

int i8 = 10 ;

i8 = ++i8;

System.out.println( "i8 =" + i8); //11

对应字节码

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

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. 第四类问题

?

1

2

3

4

5

//第4类问题:

int i9 = 10 ;

int i10 = i9++ + ++i9; //10+12

System.out.println( "i9 =" + i9); //12

System.out.println( "i10 =" + i10); //22

对应字节码为

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

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处的值入栈执行输出语句

到此这篇关于浅谈JVM 底层解析 i++和 ++i 区别的文章就介绍到这了,更多相关JVM 底层解析 i++和 ++i 区别内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!

原文链接:https://blog.csdn.net/demo_yo/article/details/118269423

查看更多关于浅谈JVM 底层解析 i++和 ++i 区别的详细内容...

  阅读:14次