Java Class 文件是 JVM 執行的基本單元,採用嚴格規範的二進制格式存儲類/接口定義。理解其結構對於 JVM 調優、字節碼操作(ASM、Javassist)、動態代理、熱部署等進階場景至關重要。本文按《Java 虛擬機規範》順序,逐節拆解 Class 文件結構。
ClassFile {
u4 magic; // 魔數:0xCAFEBABE
u2 minor_version; // 次版本號
u2 major_version; // 主版本號
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags; // 類訪問標志
u2 this_class; // 類索引
u2 super_class; // 父類索引
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
所有數據項按順序緊湊排列,無分隔符,採用大端序存儲。
major_version 決定 JVM 能否加載。JDK 8 = 52 (0x34),JDK 11 = 55,JDK 17 = 61。高版本 JVM 向下兼容,低版本無法加載高版本 Class(拋出 UnsupportedClassVersionError)。常量池是變長數組,索引從 1 開始(0 表示「不引用任何常量」)。存儲兩大類常量:
常見常量項類型(tag 標識):
| 類型 | tag | 結構示例 |
|---|---|---|
| CONSTANT_Utf8 | 1 | 長度 + 字節數組(MUTF-8 編碼) |
| CONSTANT_Integer | 3 | 4 字節 int 值 |
| CONSTANT_Class | 7 | name_index → CONSTANT_Utf8 |
| CONSTANT_String | 8 | string_index → CONSTANT_Utf8 |
| CONSTANT_Fieldref | 9 | class_index + name_and_type_index |
| CONSTANT_Methodref | 10 | class_index + name_and_type_index |
| CONSTANT_NameAndType | 12 | name_index + descriptor_index |
標識類/接口層級訪問屬性,常用標志位:
ACC_PUBLIC (0x0001):public 類ACC_FINAL (0x0010):final 類ACC_SUPER (0x0020):JDK 1.2+ 編譯標志,修正 invokesuper 語義ACC_INTERFACE (0x0200):接口而非類ACC_ABSTRACT (0x0400):abstract 類ACC_SYNTHETIC (0x1000):編譯器生成,非源碼顯式定義ACC_ANNOTATION (0x2000):註解類型ACC_ENUM (0x4000):枚舉類型示例:public class Test {} → access_flags = 0x0021 (ACC_PUBLIC | ACC_SUPER)
this_class:指向常量池 CONSTANT_Class 索引,表示當前類super_class:指向父類 CONSTANT_Class,Object 類此項為 0interfaces[]:實現的接口列表,每項指向 CONSTANT_Class描述類/實例變量(不含方法局部變量)。每項結構:
field_info {
u2 access_flags; // 訪問標志:public/private/protected/static/final/volatile/transient/synthetic/enum
u2 name_index; // 字段名 → CONSTANT_Utf8
u2 descriptor_index; // 描述符 → CONSTANT_Utf8
u2 attributes_count;
attribute_info attributes[attributes_count];
}
描述符規則:
B/C/D/F/I/J/S/Z(byte/char/double/float/int/long/short/boolean)L全限定名; 如 Ljava/lang/String;[ 前綴,如 [[I 表示 int[][]結構與字段表類似,核心差異在屬性表中包含 Code 屬性(方法字節碼、操作數棧、局部變量表、異常表、行號表、局部變量類型表)。
method_info {
u2 access_flags; // public/private/protected/static/final/synchronized/bridge/varargs/native/abstract/strictfp/synthetic
u2 name_index; // 方法名
u2 descriptor_index; // 方法描述符:(參數描述符)返回描述符
u2 attributes_count;
attribute_info attributes[attributes_count];
}
方法描述符示例:(ILjava/lang/String;)V 表示 void method(int, String)。
| 屬性名 | 所在位置 | 作用 |
|---|---|---|
| Code | method_info | 字節碼、操作數棧深度、局部變量表、異常處理表、行號表 |
| ConstantValue | field_info | final static 基本類型/String 常量值 |
| Exceptions | method_info | 方法拋出的受檢異常列表 |
| SourceFile | ClassFile | 源文件名 |
| LineNumberTable | Code | 字節碼偏移量 ↔ 源碼行號映射 |
| LocalVariableTable | Code | 局部變量作用域、名稱、描述符、槽位 |
| Signature | Class/field/method | 泛型簽名信息 |
| RuntimeVisibleAnnotations | Class/field/method | 運行時可見註解 |
javap -v ClassName:JDK 自帶,詳細反編譯輸出javap -c ClassName:僅輸出字節碼指令掌握 Class 文件格式,等於拿到了 JVM 執行引擎的「設計圖紙」,是從 Java 應用開發者進階為平台級工程師的必經之路。