使用javap深入理解Java整型常量和整型變數的區別
我下圖程式碼第五行和第九行分別定義了一個整型變數和一個整型常量:
static final int number1 = 512;
static int number3 = 545;
Java程式設計師都知道兩者的區別。
下面我們就用javap將.class檔案反編譯出來然後深入研究Java裡整型變數和整型常量的區別。
使用命令列javap -c constant.ConstantFolding檢視.class檔案反編譯出來的位元組碼:
結果:
這些位元組碼指令的說明,在wikipedia裡有說明:
我們們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的細節
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/24475491/viewspace-2212997/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 整型字元常量和字元字面量的區別 sizeof(char) 和 sizeof('a')字元
- 深入理解 Java 的整型型別:如何實現 2+2=5?Java型別
- 交換兩個整型變數變數
- c語言字元常量當做整型C語言字元
- Java整型資料型別(詳解)Java資料型別
- Java工具類 NumberUtils 對整型數字的引用Java
- 什麼是整型型別?Python整型詳細介紹型別Python
- Java隨談(六)## 我們真的理解 Java 裡的整型嗎?Java
- java常量和變數Java變數
- 二,Java中常量與變數的理解Java變數
- 四:java常量和變數Java變數
- 理解Python中整型物件儲存的位置Python物件
- 什麼是整型?Python整型詳細介紹Python
- Java中HashMap和TreeMap的區別深入理解JavaHashMap
- 加了強型別如何將請求引數轉為整型型別
- Python基本資料型別之整型Python資料型別
- 深入理解equals和==的區別
- Java基礎-成員變數和區域性變數的區別Java變數
- java變數及常量Java變數
- 深入理解 Python 虛擬機器:整型(int)的實現原理及原始碼剖析Python虛擬機原始碼
- PostgreSQL整型相除規範SQL
- 正確理解和使用JAVA中的字串常量池Java字串
- 使用var和不使用var宣告變數的區別變數
- 成員變數和區域性變數的區別變數
- 【譯】自動生成整型序列
- sqlplus中define定義的常量和variable定義的變數的區別!SQL變數
- 指標常量和常量指標的區別指標
- Swift(一)常量和變數Swift變數
- Java第三天【變數、常量、資料型別】Java變數資料型別
- MySQL 五種整型資料型別的範圍與區別 tinyint smallint mediumint int bigintMySql資料型別
- Spark 外部變數和BroadCast變數的區別Spark變數AST
- 全域性變數和靜態變數的區別變數
- strtol() 字串轉長整型函式字串函式
- C語言---整型字串轉換C語言字串
- golang常用手冊:資料型別、變數和常量Golang資料型別變數
- [譯]BigInt:JavaScript 中的任意精度整型JavaScript
- Python 中整型物件儲存的位置Python物件
- Oracle資料庫中的整型表示法Oracle資料庫