1、知识补充
JVM虚拟机里面有很多结构,本题主要用到局部变量表和操作数栈。
局部变量表
局部变量表是一组变量值存储空间,用于存放方法参数和方法内部定义的局部变量。在Java程序被编译成Class文件时,就在方法的Code属性的max_locals数据项中确定了该方法所需要分配的最大局部变量表的容量。
局部变量表的容量以变量槽(Slot)为最小单位,32位虚拟机中一个Slot可以存放一个32位以内的数据类型(boolean、byte、char、short、int、float、reference和returnAddress八种)。
操作数栈
Java虚拟机的解释执行引擎被称为"基于栈的执行引擎",其中所指的栈就是指-操作数栈。操作数栈也常被称为操作栈。
和局部变量区一样,操作数栈也是被组织成一个以字长为单位的数组。 它不是通过索引来访问,而是通过标准的栈操作—压栈和出栈—来访问的。
虚拟机在操作数栈中存储数据的方式和在局部变量区中是一样的:如int、long、float、double、reference和returnType的存储。对于byte、short以及char类型的值在压入到操作数栈之前,也会被转换为int。
虚拟机把操作数栈作为它的工作区——大多数指令都要从这里弹出数据,执行运算,然后把结果压回操作数栈。
相关JVM字节码指令:
begin
iload_0 // 将局部变量中索引为0的数据压入到操作数栈中
iload_1 // 将局部变量中索引为1的数据压入到操作数栈中
iadd // 从操作数栈中弹出两个数据进行相加,然后将计算的结果压入栈中
istore_2 // 把操作数栈计算的结果存储到局部变量区索引为2的位置。
end
2、程序分析
(1) 代码 i = i++ 分析:
① 等号“=”赋值的时候,先计算等号右边的,再将等号右边的结果赋值给左边。
int i = 1;此时将 i 存储到局部变量表。
② 因为是 i 要参与计算的,要把操作数压到操作数栈里面进行运算。
③ 此时,i++自增,自增导致i从1变成了2,将局部变量表中1变成2。
④ 此时,计算完了,还没有赋值, i = i++,将操作数栈的的1赋值给局部变量表中的2,覆盖。
⑤ 小结:i = i++ 执行的结果是1。
(2) 代码 int j = i++ 分析:
① 还是先将 i 值压入栈中
② 然后 i 自增,在局部变量表进行自增,变成2
③ 然后将操作数栈中的1赋值给j
④ 小结:最终j的结果是1
(3) 代码 int k = i + ++i * i++ 分析:
① 先将 i 的值压入栈中
注意:int k = i + ++i * i++;压入栈的过程是从 i 开始的,按照顺序进行。
② 然后是++i,i前自增后,局部变量表中的 i 变成3,并压入栈中。
③ 然后计算i++,先将操作数压入操作栈中,然后i在局部变量表中自增1
④ 然后再操作数中计算结果,每一步计算的结果压入栈中。最终结果赋值给局部变量表中的K
⑤ 小结,最终的结果是k = 11;i = 4;j = 1;
小结
JVM中class字节码指令如下:
iconst_1:定义常量1
istore_1[i];对第一个变量i赋值
iload_1[i]:将i压入操作数栈中
iinc_1 1[i]:局部变量表i自增1
istore_2 [j]:将第二个参数j压入栈中
imul:执行乘法
iadd:执行加法
istore_3 [k]:将第三个参数j压入栈中,执行结果返回