您的位置:  首页 > 技术 > java语言 > 正文

从 JVM 层面理解 i++ 和 ++i 的真正区别!

2021-09-01 17:00 https://my.oschina.net/javaroad/blog/5217801 Java技术栈 次阅读 条评论

前言

如果只用普通的知识解释i++和++i的话

  • i++ 先将i赋值再++
  • ++i 先++再赋值

但是这简单的回答并不能入吸引面试官的眼球,如果用java字节码指令分析则效果完全不同。

代码实现

public class OperandStackTest {

/**

    程序员面试过程中, 常见的i++和++i 的区别

     */

    public static void add(){

        //第1类问题:

        int i1 = 10;

        i1++;

        System.out.println(i1);//11



        int i2 = 10;

        ++i2;

        System.out.println(i2);//11



        //第2类问题:

        int i3 = 10;

        int i4 = i3++;

        System.out.println(i3);//11

        System.out.println(i4);//10



        int 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);//10



        int 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: 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

解释以上运行结果

第一类问题

对应的指令为

先将i1的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表0的位置,然后执行iinc将0位置的值+1,然后将局部变量表0位置的数入栈执行输出操作

所以i1的值为11

先将i2的值为10入栈(bipush),然后将int类型的值从栈中存到局部变量表1的位置,然后执行iinc将1位置的值+1,然后将局部变量表1位置的数入栈执行输出操作

所以i2的值为11

总结

由于没有赋值操作,区别不大。

第二类问题

先将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/article/details/118269423

版权声明:本文为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开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接