目录
一:起因:以下代码为什么打印值为0?
二:分析什么原因呢?
那么直接看i++的操作指令吧;
那么++i的操作指令呢?执行的流程就不画了。
三:总结
一:起因:以下代码为什么打印值为0?
int i = 0;
int j = i++;
System.out.println(j); // 打印值 0
int i = 0;
int j = ++i;
System.out.println(j); // 打印值 1
二:分析什么原因呢?
那么直接看i++的操作指令吧;
0: iconst_0 //将int类型常量0压入栈
1: istore_1 // 将int类型值存入局部变量1
2: iload_1 //从局部变量1中装载int类型值
3: iinc 1, 1 //把一个常量值加到一个int类型的局部变量上
6: istore_2 //将int类型值存入局部变量2
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 从类中获取静态字段
10: iload_2 //从局部变量2中装载int类型值
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
14: return
?
上面的指令执行过程:
? ? ? ? 1:int值0入栈;
?2:把0赋值给局部变量1,即:i= 0 ;
?3: 局部变量1 的值入栈,放到操作数栈中;
?4:执行自增操作,注意这里jvm iinc的说明是 把常量值加给int类型的局部变量上,值得注意的是下面的行号缺失了几行。我的理解是:jvm在底层直接操作了这个运算并且赋值给了变量1;
5:把操作数栈的值赋值给变量2,即:j= 0;? 这个值在自增前已经入栈了;
6:把变量2 的值入栈;
?7:也就是打印结果为0;
那么++i的操作指令呢?执行的流程就不画了。
0: iconst_0 //把常量值0 入栈
1: istore_1 //给变量1赋值
2: iinc 1, 1 //把常量值加给一个intl=类型的局部变量(1)
5: iload_1 //把变量1入栈
6: istore_2 //把int类型的值赋值给变量2
7: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
10: iload_2 //将变量2的值入栈
11: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
三:总结
注意对比下iinc上下的指令;
i++ 是在 执行iload指令之后执行的iinc指令,啥意思呢? i++在执行iinc指令之前已经把变量1的值加入到操作数栈了,而 ++i? 是赋完变量1的值后 直接执行iinc(自增操作)后,执行iload_2,把变量2的值加入到操作数栈,也就是说 此时操作数栈的值是执行 (iinc指令)?自增后的值。
? ? ? ? 有些文档说 i++ 是先赋值 在计算 ,而 ++i是先计算再赋值。
个人理解:应该是不正确的。为啥呢? 对比两者之间的指令,不难发现,赋值都是在iinc指令之后,只是i++在执行自增前已经把变量i的值写入到操作数栈了,在赋值的时是用的自增前的值,而++i是在执行iinc指令后从局部变量表中拿的值赋值给变量2的。
|