在看面试题的时候看到++i和i++的题目,我们都知道他们是加操作先后的差别,但是仔细想想,我们是否真的懂了?
我们思考一个问题:下面程序的运行结果为什么是这样?
public static void main(String[] args) {
int i=10;
int n=15;
i=i++;
System.out.println(i);
}
想要弄清楚程序的输出结果为什么为10,我们需要对代码执行步骤进行解析:
首先,主方法栈帧初始化内存,然后给i赋值10,给n赋值15
然后进行i=i++;的操作,重点就是这里
我们都知道i=i++;是个复合操作,我们先试着将它分开,可能的计算有两种情况:
- i=i; i=i+1;
- i=i+1; i=i;
这时候就有同学有疑惑了,无论是那种情况,i最后的值都应该是11啊,怎么会输出10呢?
其实,我们看看字节码的逻辑,Java源文件编译为class文件,Java虚拟机实际执行的是class文件
上面代码编译后的字节码如下:
public static void main(String[] args) {
int i = 10;
int n = true;
byte var10000 = i;
int var3 = i + 1;
i = var10000;
System.out.println(i);
}
可以看到它里面使用了var10000来作为一个中间变量存储i开始的值(10),最后赋给i的还是是中间变量的值,它相当于一个缓存吧。
至于为啥会编译成这样,想要研究的同学可以研究下编译器的相关机制。
我们都知道CPU每次运算后的值不会直接写到主存中,而是先存放再Cache中再写入主存,这里类似,每条语句的运算结果其实都不会直接赋给那个变量,而是先通过一种中间缓存机制存放,然后赋给相应的变量。
类似的,i=++i;的问题也就一目了然了
同理我们看一下i=++i编译成calss码后是什么样子的:
源码:
public static void main(String[] args) {
int i=10;
int n=15;
i = i++;
System.out.println(i);
int j=9;
j = ++j;
System.out.println(j);
}
字节码:
public static void main(String[] args) {
int i = 10;
int n = true;
byte var10000 = i;
int var4 = i + 1;
i = var10000;
System.out.println(i);
int j = 9;
int j = j + 1;
System.out.println(j);
}
这时,我们是不是能理解为啥i=i++问题了呢?