讀懂 Java 位元組碼(3)
要檢視 class 的位元組碼有很多方式,這裡我選擇自己比較喜歡 vscode 提供外掛來檢視,下載下圖的外掛安裝後就可以在 vscode 中檢視位元組碼檔案。

hexdump.JPG
表示 coffee baby 這是模數,也是校驗這個檔案是 JVM 認可的位元組碼檔案。如果要是我開發的就修改為 ZI EA 呵呵

byte_code.JPG
魔數
CA FE BA BE
前u4 前四個位元組是魔數,表示 coffee baby 這是模數,也是校驗這個檔案是 JVM 認可的位元組碼檔案。如果要是我開發的就修改為 ZI EA 呵呵
版本資訊
00 00 00 34
- 00 00 前兩位代表小版本號
- 00 34 表示 52 是 java 版本號 52 對應 java 1.8
java version "1.8.0_171" Java(TM) SE Runtime Environment (build 1.8.0_171-b11) Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)
常量池數量
24(1 * 16 + 8 = 24) 代表有 23 個常量,為什麼是 23 常量而不是 24 常量,因為 0 作為 JVM 保留常量,常量是從 1 開始的,所以需要減去 1 為 24
0A
常量池是以資料表的結構來儲存常量資訊,這裡表是按既定的順序來組織一類資料。每一個常量根據型別不同而有不同的長度。那麼也就是說常量池的長度是可變的。JVM 如何知道讀取到哪一位置就結束了常量池呢。首先根據 18(24)進行一條一條地讀取常量,每一個常量根據型別可以計算出其長度。這樣 JVM 就很容易就可以計算出常量池結束位置。
在開始之前先介紹一下在位元組碼有關基本型別和引用型別表示,在位元組碼檔案中要儘可能節省空間,所以使用大寫字母來表示型別,而且位元組碼是給機器閱讀的。
基本型別 I(int)

constant_table.png
這裡列出 12 中基本常量,在 JDK 1.7 之後又新增了三種常量,這裡不作為重點所以沒有羅列出。我們先看一下表,根據結構,常量名稱 CONSTANT_utf8_info ,tag 表示常量型別佔一個位元組,這裡的 U1 表示一個位元組,然後是長度為 U2 兩個位元組,先不說了我們通過表來在位元組碼中讀取幾個常量就能明白了。
我們使用以上表對應去查詢就可以讀懂常量池的位元組碼代表含義了。
接著表示常量數量位元組碼向下讀取
0A
表示 11 對應表中的 CONSTANT_InterfaceMethodref_info 好,找到型別我們繼續向下看,第一個兩個位元組表示引用指向該欄位或名稱常量項的索引,繼續向下兩個位元組為
我們可以現在 javap 編譯後可讀性較高的檔案看一下 4 是什麼東西
#4 = Class#23// java/lang/Object
04 表示指向 4 ,其實就是定義建構函式的 <init>
接下來是兩個位元組是
14 轉為 20 (16 + 4)這裡指向一個 20 的在可讀 class 檔案中內容為兩個引用 7 和 8 ,讓後將 7 和 8 內容獲取進行簡單拼接就是 <init>()V
#7 = Utf8<init> #8 = Utf8()V #9 = Utf8Code
#20 = NameAndType#7:#8// "<init>":()V
使用 javap 命令將位元組碼檔案呈現可讀檔案中對應下面位元組碼
0A 00 04 00 14
的文字為
#1 = Methodref#4.#20// java/lang/Object."<init>":()V
1 代表第一行,0A 代表 Methodref 常量的型別,#4 #20 表示兩個引用,通過獲取兩個引用組成字串為 java/lang/Object."<init>":()V。