i++和++i的区别

133 阅读2分钟

首先我们观察以下代码:

public class Main7 {
    public static void main(String[] args) {
        int i = 0;
        i = i++;
        System.out.println(i); // 输出:0
    }
}

上面代码的字节码文件反编译后的执行过程如下:

image.png 下面我来逐步解释上面的代码:

1.iconst_0: 将立即数0放入操作数栈中

image.png

  1. istore_1: 将操作数栈顶的值放到局部变量表1的位置

image.png

到这一步就相当于执行了int i = 0;这段代码,局部变量表索引1中的数据其实就是i

3.然后继续执行iload_1,将局部变量表索引1位置的值放到操作数栈中

image.png

4.接着执行iinc 1, 1将局部变量表索引1位置的值+1, 到这里完成i++

image.png

5.最后一步istore_1将操作数栈中的值放入到索引1的位置,相当于执行了i = i++

image.png

我们通过观察可以发现i++在执行完innc 1, 1时i确实变成了1,但由于赋值操作最终又变成了0

当我们将代码中第二行换成i = ++i;时,底层会将iload_1iinc 1,1的执行过程互换,先执行iinc 1,1,此时操作数栈中存的是1,然后执行iload_1,在执行步骤五,此时i中存的值将会是1

我们再看一道题,通过手写反编译结果然后和实际结果进行对比

int i = 2;
int y = i++ + ++i;
iconst_2 // 将立即数2压入操作数栈 --> 栈内:2
istore_1 // 将栈顶的值放入局部变量表[1] --> 栈空 | 1:2
执行完 int i = 2

iload_1  // 将局部变量表[1]的值入栈 --> 栈内:2  | 1:2
iinc 1,1 // 将局部变量表[1]的值+1 --> 栈内:2 | 1:3
执行完i++

iinc 1,1 // 将局部变量表[1]的值+1 --> 栈内:2 | 1:4
iload_1  // 将局部变量表[1]的值入栈 --> 栈内:2 4 | 1:4
执行完++i

iadd 将栈顶前两个数相加 2 + 4 --> 栈内:6 | 1:4
执行完i++ + ++i

istore_2 //  将栈顶的值放入局部变量表[1] --> 栈空 | 1:4, 2:6
执行完int y = i++ + ++i

image.png

对字节码文件执行javap -v Main.class后可以看到,结果和我们手写的一致。

image.png

这就是i++和++i的底层实现。