先看一道阿里雲大學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
現在,你是否明白了呢