類文件結構
類文件是一組以8位字節為基礎的二進制流,各個數據必須嚴格按照順序排列在類文件中,并且只有兩種數據類型
- 無符號數: 描述數字、索引引用、數量值或者UTF-8編碼的字符串
- 表: 由無符號數或其它表作為數據結構的符合數據類型
名稱 | 類型 | 數量 |
---|---|---|
magic | u4 | 1 |
minor_version | u2 | 1 |
major_version | u2 | 1 |
constant_pool_count | u2 | 1 |
constant_pool | cp_info | constant_pool_count-1 |
access_flag | u2 | 1 |
this_class | u2 | 1 |
super_class | u2 | 1 |
interfaces_count | u2 | 1 |
interfaces | u2 | 1 |
fields_count | u2 | 1 |
field_info | fields | fields_count |
methods_count | u2 | 1 |
methods | methods_info | methods_count |
atrributes_count | u2 | 1 |
atrributes | atrribute_info | atrributes_count |
魔數和class文件版本
每個class文件頭4個字節稱為魔數(magic),用于確定這個class文件是否能被虛擬機接受,class文件魔數為0xCAFEBABE。
緊接著魔數后4個字節是class文件版本號,第5和第6字節是次版本號(minor_version),第7和第8字節是主版本號(major_version)
常量池
主版本號之后是常量池入口,常量池是class文件結構中與與其它數據關聯最多的數據類型。常量池入口有一個u2類型的數據,代表常量池容量計數(constant_pool_count),這個值從1開始,0有特殊作用,表示在特定情況下不引用任何一個常量池項目。
常量池中主要存放一下兩種常量
- 字面量(Literal): 常量,如文本字符串和被聲明為final的常量值等
- 符號引用(Symbolic Reference):
- 類和接口的全限定名
- 字段的名稱和描述符
- 方法的名稱和描述符
訪問標記
常量池之后是訪問標記(access_flag),用于識別一些類或接口的訪問信息
標記名稱 | 標記值 | 含義 |
---|---|---|
ACC_PUBLIC | 0x0001 | 是否為public |
ACC_FINAL | 0x0010 | 是否為final,只有類可以設置 |
ACC_SUPER | 0x0020 | 是否允許使用invokespecial字節碼指令,JDK 1.2之后為true |
ACC_INTERFACE | 0x0200 | 是否為接口 |
ACC_ABSTRACT | 0x0400 | 是否為abstract類型,接口和抽象類為true,其它為false |
ACC_SYNTHETIC | 0x1000 | 非用戶代碼產生 |
ACC_ANNOTATION | 0x2000 | 是否為注解 |
ACC_ENUM | 0x4000 | 是否為枚舉 |
類索引、父類索引和接口索引集合
- 類索引(this_class): 用于確定這個類的全限定名
- 父類索引(super_class)是u2類型: 用于確定這個父類的全限定名
- 接口索引(interfaces_count): 用來描述這個類實現了哪些接口,是一組u2類型的數據集合
字段表集合
- 字段表(field_info): 用于描述接口或類中聲明的變量
- 字段(fields): 包含了類級別變量或實例變量,但不包含方法內部聲明的變量
字段表結構
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
access_flags | u2 | 1 | 訪問限定標記 |
name_index | u2 | 1 | 對常量池引用,字段的簡單名字 |
descriptor_index | u2 | 1 | 對常量池引用,字段和方法的描述符 |
attributes_count | u2 | 1 | |
attributes | attributes_info | 1 |
字段訪問標志
|ACC_PUBLIC| 0x0001 | 是否為public|
|ACC_PRIVATE| 0x0002 | 是否為private|
|ACC_PROTECTED| 0x0004 | 是否為protected|
|ACC_STATIC| 0x0008| 是否為static|
|ACC_FINAL| 0x0010| 是否為final|
|ACC_VOLATILE| 0x0040| 是否為volitale|
|ACC_TRANSIENT| 0x0080| 是否為transient|
|ACC_SYNTHETIC| 0x1000| 是否由編譯器自動產生|
|ACC_ENUM| 0x4000| 是否為枚舉|
方法表集合
和字段表集合類似
屬性表集合
屬性表(attributes_info)用于描述某些場景專有的信息。
名稱 | 使用位置 | 含義 |
---|---|---|
Code | 方法表 | Java代碼變異成的字節碼指令 |
ConstantValue | 字段表 | final關鍵定義的常量 |
Deprecated | 類、方法和字段表 | 被聲明為deprecated的方法和字段 |
Execeptions | 方法表 | 方法跑出的異常 |
InnerClass | 類方法 | 內部類列表 |
LineNumberTable | Code屬性 | Java源碼的行號與字節指令的對應關系 |
LocalVariableTable | Code屬性 | 方法的局部變量描述 |
SourceFile | 類文件 | 源文件名稱 |
Synthetic | 類、方法和字段表 | 表示方法或字段為編譯器自動生成 |
code屬性
Java方法體里的代碼被編譯器處理后最終變成字節碼存在code屬性內
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 指向CONSTANT_Utf8_info常量的索引,固定為Code |
attribute_length | u4 | 1 | 屬性值的長度 |
max_stack | u2 | 1 | 操作棧最大深度,虛擬機運行時需要根據這個值來分配棧幀的棧深度 |
max_locals | u2 | 1 | 表示局部變量所需的儲存空間,單位是slot,是虛擬機為局部變量分配內存所使用的最小單位(1 slot = 32bit) |
code_length | u4 | 1 | 字節碼的長度,雖然是u4,但是字節碼長度不能超過65535 |
code | u1 | code_length | 儲存字節碼 |
exception_table_length | u2 | 1 | |
exception_table | exception_info | 1 | |
attribues_count | u2 | 1 | |
attributes | attribute_info | attribues_count |
Exception屬性
用于列舉出方法中可能拋出的受查異常
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | |
attribute_length | u4 | 1 | 屬性值的長度 |
number_of_exceptions | u2 | 1 | |
exception_index_table | u2 | number_of_exceptions |
LineNumberTable屬性
用于描述Java源代碼和字節碼行號(偏移量)之間的對應關系,不是運行時必須的屬性,如果不生成該屬性就無法再拋出異常時返回代碼中對應的行號。
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度 |
line_number_table_Length | u2 | 1 | |
line_number_table | line_number_info | line_number_table_length |
LocalVariableTable屬性
用于描述棧幀中局部變量表中的變量與Java源碼中定義的變量之間的關系,不是運行時必須的屬性,如果沒有生成所有參數名稱都將丟失
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度 |
local_variable_table_Length | u2 | 1 | |
local_variable_table | local\ _variable_info | local_variable_table_length |
local_variable_info結構
名稱 | 類型 | 數量 | 說明 | |
---|---|---|---|---|
start_pc | u2 | 1 | 這個局部變量聲明周期開始時的字節碼偏移量 | |
length | u2 | 1 | 這個局部變量聲明周期開始時的字節碼作用范圍的長度 | |
name_index | u2 | 1 | 指向CONSTANT_Utf8_info常量的索引,代表局部變量的名稱 | |
descriptor_index | 1 | 指向CONSTANT_Utf8_info常量的索引,代表局部變量的描述符 | ||
index | 1 | u2 | 表示這個局部變量在棧幀局部變量中slot的位置 |
SourceFile屬性
用于記錄生成這個class文件源代碼的名稱,是可選的,如果不生成這個屬性,拋出異常時不會顯示出錯代碼的文件名。
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度 |
sourcefule_index | u2 | 1 | 指向CONSTANT_Utf8_info常量的索引,常量值時源碼文件的文件名 |
ConstantValue屬性
ConstantValue屬性的作用是通知虛擬機自動為靜態變量賦值,只有被static修飾的變量才能用這個屬性
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度 |
constant_value_index | u2 | 1 | 指向常量池的引用 |
InnerClasses屬性
InnerClasses屬性用于記錄內部類與宿主類之間的關聯,如果一個類中有內部類,則會生成InnerClass屬性。
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度 |
nubmber_of_classes | u2 | 1 | 代表記錄多少個內部類信息 |
inner_class | inner_class_info | nubmber_of_classes |
inner_class_info
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
inner_class_info_index | u2 | 1 | 指向CONSTANT_Class_info常量的索引,代表內部類的符號引用 |
outter_class_info_index | u2 | 1 | 指向CONSTANT_Class_info常量的索引,代表宿主類的符號引用 |
inner_name_index | u2 | 1 | 指向CONSTANT_Utf8_info常量的索引,代表這個內部類的名稱,如果是匿名內部類則為0 |
inner_name_access_flag | u2 | 1 | 內部類的訪問標志 |
Deprecated屬性
表示某個類、字段或方法不再推薦使用
Synthetic屬性
表示該字段和方法是不是有Java源碼直接生成的
名稱 | 類型 | 數量 | 說明 |
---|---|---|---|
attribute_name_index | u2 | 1 | 屬性值的索引 |
attribute_length | u4 | 1 | 屬性值的長度,值必須為0x00000000 |
參考
- 深入理解Java虛擬機, 周志明