理解 Class 文件結構與字節碼指令,是進階 JVM 調優、框架原理分析、動態代理生成的必修課。本文以《深入理解 Java 虛擬機》為藍本,通過 javap 實戰拆解一個簡單類的編譯產物。
// TestClass.java
package compile;
public class TestClass {
private int m;
public int inc() { return m + 1; }
}
編譯並反編譯:
javac -g TestClass.java # -g 保留行號、局部變量表等調試信息 javap -c TestClass > TCC.txt # -c 輸出方法字節碼 javap -verbose TestClass > TCV.txt # -verbose 輸出完整結構(常量池、版本、棧幀等)
0xCAFEBABE(識別 Class 文件)。50.0 → JDK 6 編譯(JDK 7=51, 8=52, 11=55, 17=61)。存放字面量、符號引用(類名、方法名、字段名、方法描述符)。#1 = Method #4.#18 表示方法引用指向常量池 #4(類)與 #18(名稱與描述符)。
關鍵結構:
CONSTANT_Class_info:類/介面符號引用。CONSTANT_Fieldref/Methodref/InterfaceMethodref:字段/方法符號引用。CONSTANT_NameAndType:名稱+描述符(如 inc:()I)。CONSTANT_Utf8:存儲字符串字面量。符號引用 → 直接引用:類加載階段的解析過程將符號引用轉為直接指針/偏移量。
每個方法包含 Code 屬性,核心子屬性:
long/double 佔 2 Slot,其餘 1 Slot)。this,static 方法無 this)。aload_0, getfield, iadd, ireturn)。<init> 字節碼逐條解析0: aload_0 // 將 slot 0 的 this 推入棧頂 1: invokespecial #1 // 調用 java/lang/Object."":()V 即 super() 4: return // void 返回
inc() 字節碼逐條解析0: aload_0 // this 入棧 1: getfield #2 // 獲取字段 m (Field #2 → m:I) 入棧 4: iconst_1 // 常量 1 入棧 5: iadd // 棧頂兩 int 相加,結果入棧 6: ireturn // 返回 int 結果
| 參數 | 作用 |
|---|---|
-c | 輸出方法字節碼(最常用) |
-l | 輸出 LineNumberTable + LocalVariableTable |
-s | 輸出方法描述符(簽名) |
-verbose | 全量輸出(含常量池、版本、棧幀詳情) |
-p | 顯示私有成員 |
-sysinfo | 顯示系統屬性 |
final、StringBuilder、Lambda 編譯產物。建議配合《Java 虛擬機規範》第 4 章(Class 文件格式)與《深入理解 JVM》第 6 章閱讀,理論結合實戰,方得精髓。