错题一 i的值输出是多少
/**
* @program: JVMDemo
* @description: test
* @author: 郑朝文
* @create: 2021-08-20 11:59
**/
public class ErrorTest {
public static void main(String[] args) {
ErrorTest inc = new ErrorTest();
int i = 0;
inc.fermin(i);
i= i ++;
System.out.println(i);
}
public void fermin(int i) {
i++;
}
}
解析 根据字节码指令来进行分析
Java虚拟机栈(JVM Stack)描述的是Java方法执行的内存模型,而JVM内存模型是基于“栈帧”的,每个栈帧中都有 局部变量表 和 操作数栈 (还有动态链接、return address等),那么JVM是如何执行这个语句的呢?通过javap大致可以将上面的两行代码翻译成如下的JVM指令执行代码。
0 new #2 <com/yi/ErrorTest>
3 dup
4 invokespecial #3 <com/yi/ErrorTest.<init> : ()V>
7 astore_1
8 iconst_0
9 istore_2
10 aload_1
11 iload_2
12 invokevirtual #4 <com/yi/ErrorTest.fermin : (I)V>
15 iload_2
16 iinc 2 by 1
19 istore_2
20 getstatic #5 <java/lang/System.out : Ljava/io/PrintStream;>
23 iload_2
24 invokevirtual #6 <java/io/PrintStream.println : (I)V>
27 return
我们从第 8 行进行分析,这个是主要的部分
第8 : 将int类型的0入栈,就是放到操作数栈顶
第9 : 将操作数栈顶的值0弹出,保存到局部变量表index值为2的位置。(该方法是类方法所以index0的位置不会保存this,方法内公有三个参数 (args,inc,i))
第10 :将index1位置的引用类型推入栈顶
第11 :将局部变量表中index 2 位置的值的副本入栈(栈顶的值为0)
第12 : 进行方法调用
第15 :将局部变量表中index 2 位置的值的副本入栈(栈顶的值为0)
第16 :iinc是对int类型的值进行自增操作,后面第一个数值2 表示,局部变量表中的index 值,说明要对此值进行iinc操作,第二个数值1表示要增加的数值(这是局部变量表index为2的值因为执行了自增操作变为1了,但是操作数栈中栈顶的值仍然是0)
第19 : 将操作数栈顶的值弹出(值0),放到局部变量表index为2的位置(旧值:1,新值 :0),覆盖了上一步局部变量表的计算结果
总结在第9和第19执行了2次将0赋值给变量i的操作(=号赋值),i++操作时在这两次操作之间执行,自增操作是对局部变量表中的值进行自增,而栈顶的值没有发生变化,这里需要注意的是保存这个初始值的地方是操作数栈而不是局部变量表,最后再将栈顶的值覆盖到局部变量表i所在的索引位置中去。