本篇文章帶給大家的內容是關於如何用javap解析Java整型常數和整型變量,有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
我下圖程式碼第五行和第九行分別定義了一個整數變數和一個整數常數:
static final int number1 = 512; static int number3 = 545;
Java程式設計師都知道兩者的差異。
下面我們就用javap將.class檔案反編譯出來然後深入研究Java裡整數變數和整數常數的差異。
使用命令列javap -c constant.ConstantFolding查看.class檔案反編譯出來的字節碼:
結果:
這些字節指令的說明,在wikipedia裡有說明:
wiki: https://en.wikipedia .org/wiki...
咱們Java程式設計師不需要把它們都背下來,只需要把這個網頁收藏起來,要用的時候當成字典來用就行:
sipush 545: 將整數545放置到堆疊上
putstatic #16:
將堆疊上的值545賦給目前類的靜態字段裡。
那麼putstatic #16裡的#16代表什麼意義?
我們再用javap -v 參數反編譯,就能看到這個類別的常數池(Constant pool). 大家看下圖藍色高亮的一行:
constant/ConstantFolding .number3:I
說明#16代表類別constant.ConstantFolding的成員number3,類型為I。
至此,這兩行字節碼指令聯合起來,實際上對應了我們寫的Java程式碼:
static int number3 = 545;
我們繼續分析javap反編譯出來的字節碼。
aload_0: 將序號為0的本地變數的引入載入到堆疊上
invokespecial: 呼叫物件實例上的成員方法,如果有回傳值,方法的回傳值會儲存到堆疊上。具體呼叫的方法由#標識,可在常數池中查詢到對應的方法名稱。
ldc: 將常數池上代號為#<數字>的常數的值從常數池載入到堆疊上。
我們從下圖的常數池列表能發現,序號為#29的常數318976正是整數常數number1(512)和整數常數(623)的積。由此可以看出, number1 * number2這個表達式,因為參與運算的兩個操作數透過STATIC和FINAL修飾成為了整型常數,因此其積在編譯期就能得到,所以編譯器在編譯時就計算出來,儲存在變數池裡,序號為#29。
那麼整數變數做乘法運算,對應的字節碼又是什麼樣的呢?
從下圖序號為3的code開始:
getstatic #16: 將類別的靜態成員#16載入到堆疊上。 #16對應的成員為number3,值為545。
getstatic #18: 將類別的靜態成員#18載入到堆疊上。 #18對應的成員為number4,值為619。
imul: 執行堆疊上兩個整數的乘法運算。
istore_2: 將結果儲存到局部變數2裡。
此時,我們Java程式碼裡的int product2 = number3 * number4就執行完了。
大家看到的剩下的藍色字節碼,都對應了下面這行列印語句。
System.out.println("Value: " + product1 + " , " + product2);
從這些字節碼也能看出,Java裡我們直接用加號進行字串拼接操作,Java編譯器在編譯時,自動使用了StringBuilder進行最佳化。
既然整數變數的乘積需要列印出來,所以字節碼的iload_2將之前用istore_2保存在局部變數2中的計算結果又載入到堆疊上,這樣乘積結果最後就能輸出了。
希望透過這個簡單的例子,大家能學會用javap去深入理解一些Java和JVM的細節。
以上是如何用javap解析Java整數常數和整數變數的詳細內容。更多資訊請關注PHP中文網其他相關文章!