zoukankan      html  css  js  c++  java
  • 从 JVM 层面理解 i++ 和 ++i 的真正区别!

    前言

    如果只用普通的知识解释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开发手册(嵩山版)》最新发布,速速下载!

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

  • 相关阅读:
    常见http状态码
    通过adb shell命令查看内存,CPU,启动时间,电量等信息
    Jmeter获取数据库数据参数化
    jmeter链接mysql数据库,sql数据库,oracle数据库
    appium 隐藏键盘
    python编码
    python:打印所有文件名字的扩展名
    python中字符串常见操作
    python中的字符串存储及切片介绍
    Ubuntu14.04安装部署bugzilla5.0.3
  • 原文地址:https://www.cnblogs.com/javastack/p/15215034.html
Copyright © 2011-2022 走看看