直面底层之字节码看i++与++i

523 阅读2分钟

前言

很多时候我们遇到一些面试 i++ 和 ++i我们很容易入坑,一不小心就落入了陷阱,本文从字节码层面看i++和++i,了解底层的实现,知其然知其所以然


一、i++ 的 坑

我们先看个小例子,下面会输出什么:

public static void main(String[] args) {
    int i = 0;
    for(int j = 0; j < 50;j++){
        i = i++;
    }
    System.out.println(i);
}

答案是0, 如果你答对了 恭喜你,答错了那我们来看下底层字节码:

public static void main(java.lang.String[]);
    Code:
       0: iconst_0  //0 加载到操作数栈顶
       1: istore_1  //操作数栈顶 放入 局部变量表第一个位置 即给i 赋初值
       2: iconst_0  // 0 加载到操作数栈顶 
       3: istore_2  // 操作数栈顶 放入局部变量表 第二个位置 即给j 赋初值
       4: iload_2   //将 j 加载到栈顶 
       5: bipush        50  //将 50 加载到栈顶
       7: if_icmpge     21  // 比较 j 和 50 如果 >= 50  则跳转至 21行 否则向下执行 
      10: iload_1      //加载i的值 到操作数栈顶 这时候还是0 
      11: iinc          1, 1 //i 的值+1,这里是直接发生在 局部变量表中的,并未到操作数栈,局部变量表值变更为2
      14: istore_1     //将操作数栈顶放到局部变量表第一个位置,也就是i的值,这时候操作数栈还是0
      15: iinc          2, 1 //j++ 
      18: goto          4  //跳转至第4行 继续执行循环
      21: getstatic     #2 // Field java/lang/System.out:Ljava/io/PrintStream;
      24: iload_1
      25: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
      28: return

我们可以看到 i++ 只操作了局部变量表,并不会和操作数栈发生关系,如果i= i++ 的结果就是 先读了i 的值 到操作数栈,然后局部变量表操作自增,然后 操作数栈又写回了 局部变量表发生了覆盖,所以结果会是 0.

那么下面代码会输出什么呢?

public static void main(String[] args) {
    int i = 0;
    for(int j = 0; j < 50;j++){
        i = ++i; 
    }
    System.out.println(i);
}

public static void main(String[] args) {
    int i = 0;
    for(int j = 0; j < 50;j++){
         ++i; 
    }
    System.out.println(i);
}

public static void main(String[] args) {
    int i = 0;
    for(int j = 0; j < 50;j++){
        i++; 
    }
    System.out.println(i);
}

这里结果都会是 50,第一种情况虽然发生了覆盖,但是 覆盖的值和 局部变量表中的值是一致的,所以是50,

第二和第三种都是操作的局部变量表,未发生覆盖,输出时才将局部变量表加载到栈顶,所以也是 50.


二、稍微复杂一点的案例

//java 代码
public static void main(String[] args) {
    int i = 0;
    i = i++ + i++ + i++ + ++i;
    System.out.println(i);
}

字节码我就不贴了,我们来分析下这个流程:

首先我们把 “=” 后面 用 + 号隔开,出现了四部分 i++ 、i++、i++、++i

第一个:会采用初始值 0, 做加法之后会+1 变为1,存入局部变量表;

第二个:会取局部变量表 的1做加法,然后 + 1后变为2,放入局部变量表;

第三个:取局部变量表的值 2 做加法,然后+1 变为3,放入局部变量表;

第四个:会将局部变量表的值+1,变为4,然后从局部变量表中取出做加法

所以最终的结果是:0+1+2+4 = 7。感兴趣的可以分析下字节码