首先我们观察以下代码:
public class Main7 {
public static void main(String[] args) {
int i = 0;
i = i++;
System.out.println(i); // 输出:0
}
}
上面代码的字节码文件反编译后的执行过程如下:
下面我来逐步解释上面的代码:
1.iconst_0: 将立即数0放入操作数栈中
istore_1: 将操作数栈顶的值放到局部变量表1的位置
到这一步就相当于执行了int i = 0;这段代码,局部变量表索引1中的数据其实就是i
3.然后继续执行iload_1,将局部变量表索引1位置的值放到操作数栈中
4.接着执行iinc 1, 1将局部变量表索引1位置的值+1, 到这里完成i++
5.最后一步istore_1将操作数栈中的值放入到索引1的位置,相当于执行了i = i++
我们通过观察可以发现i++在执行完innc 1, 1时i确实变成了1,但由于赋值操作最终又变成了0
当我们将代码中第二行换成i = ++i;时,底层会将iload_1和iinc 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
对字节码文件执行javap -v Main.class后可以看到,结果和我们手写的一致。
这就是i++和++i的底层实现。