面试时经常碰到这样的面试题
int i = 0;
i = i++;
i输出多少?
int i = 0;
i = ++i;
i输出多少?
网上有很多文章,但是大部分都是模棱两可,甚至自己都说不清,接下来我将从JVM字节码指令的角度来说明
参考来源:《深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)》
首先,明确几个概念
栈帧
1、Java的方法以栈帧的形式存储在虚拟机栈中;
2、每个方法栈帧包含局部变量表、操作数栈、动态链接、方法出口共四个部分,本文仅涉及到局部变量表、操作数栈两部分;
3、局部变量表以变量槽(slot)的方式存储局部变量(local variable),可以简单理解为数组,举个例子
int a = 10;
int b = 11;
上述代码片段对应的局部变量表如下图所示
4、操作数栈是大部分字节码指令集直接操作的对象,就是普通的栈结构。
自增相关指令集
iconst_<i>
将int型i压入操作数栈
istore_<n>
将操作数栈顶元素退栈,存储在局部变量表slot n处,该指令可以理解为赋值指令,即将操作数栈顶元素赋值给局部变量;
iload_<n>
将局部变量表slot n处的数据压入操作数栈顶
iinc index, const
将slot index处的数据直接加上const,该指令的特别之处在于直接操作局部变量表,不经过操作数栈。
实例分析
示例代码
public class Test1 {
public static void main(String[] args) throws Exception {
System.out.println(inc1());
System.out.println(inc2());
}
public static int inc1() {
int i = 0;
i = i++;
return i;
}
public static int inc2() {
int i = 0;
i = ++i;
return i;
}
}
javap查看class文件对应的字节码指令
javap -v Test1
方法inc1()对应的指令如下图
方法inc2()对应的指令如下图
两图对比,可以发现,i++和++i最大的区别在于iinc和iload两个指令的执行顺序不同,因此造成了inc1()返回值为0,而inc2()返回值为1。
每行代码对应的指令见下图
public static int inc1() {
/* iconst_0
* istore_1
*/
int i = 0;
/*
* iload_1
* iinc 1,1
* istore_1
*/
i = i++;
return i;
}
public static int inc2() {
/* iconst_0
* istore_1
*/
int i = 0;
/*
* iinc 1,1
* iload_1
* istore_1
*/
i = ++i;
return i;
}