先看一道阿里云大学Java基础自测-初级难度的题
很显然操作顺序先乘2再加1,结果101。GAME OVER!
WTF!结果是100,执手相看结果,竟无语凝噎。
-------------------------------------华丽丽的分割线---------------------------------------------
看看它的背后究竟发生了什么:
1、javac -- $ javac Test.java
先将这段代码编译成class文件;
2、javap -- $ javap -v -c -l Test.class
JDK自带的反解析工具(https://blog.csdn.net/w372426096/article/details/81664431 这篇文章详细介绍了javap的命令)
然后就能看到下面这段执行过程
再来解读一下这个过程,就只看main方法的部分
大概说下上图中的栈帧:每当线程调用一个Java方法时,JVM就会在该线程对应的栈中压入一个帧,Java中的栈就是由很多栈帧组成的。栈帧由三部分组成:局部变量区、操作数栈、帧数据区。
bipush、istore_1:这两步就是声明一个数值为50,并把它赋值给下标索引为1的变量;
iload_1:将下标索引为1的int变量的值压入栈中;
iinc 1,1:这一步就是说明了++的值去哪了,将指定下标索引的int值+1,这一步的操作并不在栈中,而且有没有赋值我也不清 楚,所以此时的变量值是50还是51?不过这并不影响结果;
iconst_2:将int型的数值2压栈;
imul:栈中的数值相乘;
istore_1:将结果赋值给下标索引为1的变量;
此时变量的值就是100,后面就是调用println方法了。
我勒个去,原来如此啊。。。
-------------------------------------------------------------------------------------------------------
那么~ ++i 为什么会改变值呢?
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: bipush 50
2: istore_1
3: iinc 1, 1 //变量自增
6: iload_1 //增加后的值入栈
7: istore_1 //再回赋值给变量
8: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
11: iload_1
12: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
15: return
LineNumberTable:
line 7: 0
line 8: 3
line 10: 8
line 12: 15
现在,你是否明白了呢