• java 自增问题 字节码角度解释


    问题场景:

    针对变量自增问题,使用字节进行解释


    问题一:变量自增,不进行赋值操作

    变量单纯的使用++的时候代码如下:

        public static void method6(){
            int i = 10;
            i++;
            System.out.println(i);
            ++i;
            System.out.println(i);
            for(int j = 0;j<10;j++){
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    对应的字节码文件如下

     0 bipush 10
     2 istore_0
     3 iinc 0 by 1
     6 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
     9 iload_0
    10 invokevirtual #5 <java/io/PrintStream.println : (I)V>
    13 iinc 0 by 1
    16 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
    19 iload_0
    20 invokevirtual #5 <java/io/PrintStream.println : (I)V>
    23 iconst_0
    24 istore_1
    25 iload_1
    26 bipush 10
    28 if_icmpge 37 (+9)
    31 iinc 1 by 1
    34 goto 25 (-9)
    37 return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可以看到3,13,31的字节码操作都是一样,因此此时++在前和在后是一样的

    对应的idea里反编译的代码如下:

    public static void method6() {
            int i = 10;
            ++i;
            System.out.println(i);
            ++i;
            System.out.println(i);
            for(int j = 0; j < 10; ++j) {
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以看出系统执行的时候都转为了++i进行执行


    问题二:自增变量进行赋值操作

    给新的变量赋值

     public void method7(){
            int i = 10;
            int a = i++;
    
            int j = 20;
            int b = ++j;
            System.out.println(b);
            System.out.println(a);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    ···
    对应的字节码文件如下:

     0 bipush 10  //操作数栈里压入10
     2 istore_1   //把操作数栈的数据保存到局部变量表,清空栈
     3 iload_1    //从局部变量表中拿出10
     4 iinc 1 by 1 //把当前栈里的数据加一放会到局部变量表,但是此时并没有出栈
     7 istore_2    //此时才会出栈,存储10到一个新的变量上
     8 bipush 20   //压入20
    10 istore_3   // 出栈保存为一个新的变量
    11 iinc 3 by 1  //直接操作局部变量表为21
    14 iload_3      //再拿出来放到栈里
    15 istore 4     //栈里弹出重新保存
    17 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
    20 iload 4
    22 invokevirtual #5 <java/io/PrintStream.println : (I)V>
    25 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
    28 iload_2
    29 invokevirtual #5 <java/io/PrintStream.println : (I)V>
    32 return
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    idea反编译的结果

        @Test
        public void method7() {
            int i = 10;
            int a = i++;
            int j = 20;
            ++j;
            System.out.println(j);
            System.out.println(a);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    可以看出赋值操作的关键就是是否提前iload数据到栈里,栈里的数据通过算术操作后很明显不会弹出,原始数据,而是直接把结果
    压入局部变量表,然后通过istore操作进行弹出.
    此外inc操作比较特殊,对于操作数栈的数据进行操作前不会先弹出数据在操作,而是不弹出数据,进行操作,操作的结果如果在局部变量表理有数据就会直接修改

    同理,如下问题也可以得到解释

        public void method8() {
            int i = 10;
            int i = i++;
            System.out.println(i);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
     0 bipush 10
     2 istore_1
     3 iload_1
     4 iinc 1 by 1
     7 istore_1
     8 getstatic #2 <java/lang/System.out : Ljava/io/PrintStream;>
    11 iload_1
    12 invokevirtual #5 <java/io/PrintStream.println : (I)V>
    15 return
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    深入Docker实战(第2版):构建、部署和优化容器化应用
    医院信息系统源码 HIS源码
    设计模式篇(Java):装饰者模式
    查看nginx当前并发连接数 - 修改最高并发数
    java-net-php-python-2020SSM大学生作业管理系统演示录像计算机毕业设计程序
    恩智浦与长城汽车、蔚来、小鹏和中汽创智等车企和供应商密集签约
    微信小程序(四十五)登入界面-简易版
    中级经济师考试题型有哪些?具体分值是多少?
    Gradle多模块项目配置
    P物质肽[DArg1, DTrp5, 7, 9, Leu11]
  • 原文地址:https://blog.csdn.net/qq_37771209/article/details/126311358