• 懂得i++和++i


    懂得i++和++i

    案例

    代码1

    package org.huangao.other.dome1;
    
    import org.junit.Test;
    
    public class Dome1 {
        @Test
        public void test1() {
            int j = 0;
            j = j++;
            System.out.println(j);
        }
    
        @Test
        public void test2() {
            int j = 0;
            j = ++j;
            System.out.println(j);
        }
    }
    
    

    结果

    test1:0
    test2:1
    

    代码2

    package org.huangao.other.dome1;
    
    import org.junit.Test;
    
    public class Dome1 {
        @Test
        public void test1() {
            int j = 0;
    //        j = j++;
            j++;
            System.out.println(j);
        }
    
        @Test
        public void test2() {
            int j = 0;
    //        j = ++j;
            ++j;
            System.out.println(j);
        }
    }
    
    

    结果

    test1:1
    test2:1
    

    ​ 可以初步分析是 j 值 对于 j++ 赋值的地方有所差异

    分析

    部分指令介绍

    ​ xload_n 将第(n+)个x类型本地变量推送至栈顶

    ​ xstore_n 将栈顶 x类型数值存入指定第(n+1)个本地变量

    代码1的指令

    D:jdk1.8.0_211injavap.exe -c org.huangao.other.dome1.Dome1
    Compiled from "Dome1.java"
    public class org.huangao.other.dome1.Dome1 {
      public org.huangao.other.dome1.Dome1();
        Code:
           0: aload_0
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return
    
      public void test1();
        Code:
           0: iconst_0
           1: istore_1
           2: iload_1
           3: iinc          1, 1
           6: istore_1
           7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          10: iload_1
          11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          14: return
    
      public void test2();
        Code:
           0: iconst_0
           1: istore_1
           2: iinc          1, 1
           5: iload_1
           6: istore_1
           7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          10: iload_1
          11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          14: return
    }
    
    Process finished with exit code 0
    
    

    分析

    ​ 首先我们先看test1 方法

    iconst_0 代表将int型 0 推送至栈顶

    istore_1 将栈顶 int 型数值存入第二个本地变量 即 j=0

    iload_1 将第二个int 型本地变量 推送至栈顶 即 j=0

    iinc 1,1 将局部变量表中1号元素自增1,此时j=1

    istore_1 将栈顶 int 型数值存入第二个本地变量

    getstatic

    iload_1

    invokevirtual

    return

    ​ 接下来看test2方法

    iconst_0 将 int 型 0 推入栈顶

    istore_1 将栈顶 int 型 数值存入第二个本地变量

    iinc 1,1 将局部变量表1 号元素 自增1 ,此时j=1

    iload_1 将第二个 int 型本地变量推送至栈顶

    istore_1 将栈顶 int 型数值 存入第二个本地变量

    getstatic

    .....

    代码2的指令

      public void test1();
        Code:
           0: iconst_0
           1: istore_1
           2: iinc          1, 1
           5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           8: iload_1
           9: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          12: return
    
      public void test2();
        Code:
           0: iconst_0
           1: istore_1
           2: iinc          1, 1
           5: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
           8: iload_1
           9: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          12: return
    

    结论

    本来局部变量表中的j已经完成了自增,但是在进行赋值的时候,是将操作栈中的数据弹出,直接进行覆盖操作

    ​ 如果站在JVM的层次来说 对于 i++ 和 ++i

    1. i++ 是先被操作数栈拿去了(先执行了load指令),然后再在局部变量表中完成了自增,但是操作数栈中还是自增前的值
    2. 而++i是在局部变量表中完成了自增(先执行了innc指令),然后再被load进行了操作数栈,所以操作数栈中保存的是自增后的值

    课后思考

        @Test
        public void test3() {
            int i = 4;
            int b = i++;
            int a = ++i;
        }
        a  6
        b  4
        
          public void test3();
        Code:
           0: iconst_4      // 将常量4推送栈顶
           1: istore_1			// 将栈顶元素4 存入第二个 本地变量 即i = 4
           2: iload_1			// 将i=4 的值 推送到栈顶
           3: iinc          1, 1    // 局部变量1号元素 +1  此时 i = 5
           6: istore_2				// 将栈顶元素 存入第三个本地变量中即 b=4
           7: iinc          1, 1     // 局部变量1号元素 +1  此时 i= 6
          10: iload_1				// 将局部变量第二个元素推i=6 推送到栈顶
          11: istore_3             // 将栈顶元素赋值到局部第三个变量即 a = 6
          12: return
    
        @Test
        public void test3() {
            int i = 4;
            i = i++;
            System.out.println(i);
            i = ++i;
            System.out.println(i);
        }
        4
        5
        
          public void test3();
        Code:
           0: iconst_4
           1: istore_1       
           2: iload_1				//栈顶元素 4
           3: iinc          1, 1    //局部变量 i+1  ;i=5
           6: istore_1				//赋值局部元素 i = 栈顶元素  i = 4 
           7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          10: iload_1
          11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          14: iinc          1, 1       // 局部变量i +1  ;i = 5
          17: iload_1				// 5 进入栈顶
          18: istore_1					// 栈顶元素5赋值给 i  ; i = 5
          19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          22: iload_1
          23: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          26: return
    
    
        @Test
        public void test3() {
            int i = 4;
            i = ++i;
            System.out.println(i);
            i = i++;
            System.out.println(i);
        }
        
        5
        5
          public void test3();
        Code:
           0: iconst_4
           1: istore_1
           2: iinc          1, 1
           5: iload_1
           6: istore_1
           7: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          10: iload_1
          11: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          14: iload_1
          15: iinc          1, 1
          18: istore_1
          19: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
          22: iload_1
          23: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
          26: return
    
  • 相关阅读:
    ES6, CommonJS, AMD, CMD,UMD模块化规范介绍及使用
    前端项目开发框架选型需考虑的4个方面
    初识webSocket及其使用
    动态组件 —— 2种方式实现动态组件的切换
    mac下anaconda安装新包
    新版docker设置国内镜像
    记一次解决Original error: UiAutomator quit before it successfully launched
    linux clion cmakelisits undefined reference 未定义引用
    苹果设备插入PC不能识别问题解决办法
    用Cucumber理解BDD行为驱动开发
  • 原文地址:https://www.cnblogs.com/huan30/p/12950612.html
Copyright © 2020-2023  润新知