- 问题来源:
- 疑问:中间变量缓存机制?
- 深入理解Java中间变量的缓存机制
看到这位大佬的测试用例,我简直惊呆了,于是决定自己测试一下,以便从JVM层面了解问题的根源
public class Test02
{
public static void main(String[] args)
{
int i = 8;
i++;
System.out.println(i);
int j = 8;
j = j++;
System.out.println(j);
}
}
2. 代码执行结果
9 83. jclasslib 后得到的 main 函数部分的字节码指令
0 bipush 8 2 istore_1 3 iinc 1 by 1 6 getstatic #24. 指令说明:9 iload_1 10 invokevirtual #3 13 bipush 8 15 istore_2 16 iload_2 17 iinc 2 by 1 20 istore_2 21 getstatic #2 24 iload_2 25 invokevirtual #3 28 return
局部变量表
① bipush:常量入栈指令,int取值范围(-128~127)
② istore_1:出栈指令,将操作数栈中的数据保存到局部变量表中1的位置
③ iload_1:加载指令,将局部变量表中1位置的数据加载到操作数栈中
- i++执行过程过程说明
| 程序计数器 | 指令 | 说明 |
|---|---|---|
| 0: | bipush 8 | 将常量8保存到操作数栈中 |
| 2: | istore_1 | 取出操作数栈顶元素8放入局部变量表1的位置处 |
| 3: | iinc 1 by 1 | 在局部变量槽1的位置上自增 |
| 9: | iload_1 | 从局部变量表中加载1位置上的值到操作数栈顶 |
补充说明:3:变量自增
① 在变量槽中自增的说法参考 从字节码理解Java中局部变量的自增/自减
② 执行3:的时候,操作数栈为空,只有局部变量表中有值
- j = j++执行过程说明
| 程序计数器 | 指令 | 说明 |
|---|---|---|
| 13: | bipush 8 | 将常量8保存到操作数栈中 |
| 15: | istore_2 | 取出操作数栈顶元素8放入局部变量表2的位置处 |
| 16: | iload_2 | 从局部变量表中加载2位置上的值到操作数栈顶 |
| 17: | iinc 2 by 1 | 在局部变量槽2的位置上自增 |
| 20: | istore_2 | 取出操作数栈顶元素8放入局部变量表2的位置处 |
| 24: | iload_2 | 从局部变量表中加载2位置上的值到操作数栈顶 |
上述执行过程梳理:
① 在执行17:自增之前,将局部变量表中的数据保存到操作数栈中
② 在局部变量槽中执行自增操作
③ 操作数栈顶元素的值保存到局部变量表中,覆盖掉执行自增后的值
④ 从局部变量表中把被覆盖掉的值加载到操作栈上,以进行后续的输出操作
两条语句的指令区别:
问题:
16::为什么要将数据保存到操作数栈中?
20::该行与赋值号=之间的关联?



