Java Class檔案結構例項分析(下)

二進位制之路發表於2018-12-18

本篇我們繼續分析Class檔案結構的方法及屬性部分內容,上節內容回顧請檢視:

Java Class檔案結構例項分析(上)

Class檔案格式資訊

image

繼續上節例項程式碼

package chapter6;
public class TestClass {
	private int m;
	public int inc() {
		return m + 1;
	}
}
複製程式碼

使用JDK1.8編譯成class檔案,然後通過WinHex開啟

image

方法

image
image

上節我們分析到欄位部分,欄位的完整地址範圍:000000E1~000000EA。

跟在欄位後面的是方法,下面繼續分析。

方法計數器(methods_count)

型別:u2
位元組地址:000000EB~000000EC
值:0x0002

說明當前類有2個方法。

第1個方法

訪問標誌(access_flags)

型別:u2
位元組地址:000000ED~000000EE
值:0x0001

查表得到對應的訪問標誌為ACC_PUBLIC。

名稱索引(name_index)

型別:u2
位元組地址:000000EF~000000F0
值:0x0007

對應常量池中的第7項常量,值為<init>,即例項初始化方法。

描述符(descriptor_index)

型別:u2
位元組地址:000000F1~000000F2
值:0x0008

對應常量池中的第8項常量,值為()V,說明該方法無引數,返回型別為void。

由前3項可知,第1個方法為類的例項初始化方法。

屬性計數器(attributes_count)

型別:u2
位元組地址:000000F3~000000F4
值:0x0001

說明該欄位有1個屬性。

屬性的通用格式如下:

image

第1個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:000000F5~000000F6
值:0x0009

對應常量池中的第9項常量,值為Code。

image

屬性值的長度(attribute_length)

型別:u4
位元組地址:000000F7~000000FA
值:0x0000002F

將0x0000002F轉換為十進位制,計算得到47。

運算元棧的最大深度(max_stack)

型別:u2
位元組地址:000000FB~000000FC
值:0x0001

即最大深度為1。運算元棧的最大深度,由編譯期決定。

區域性變數的個數(max_locals)

型別:u2
位元組地址:000000FD~000000FE
值:0x0001

即區域性變數的個數為1。區域性變數的個數,由編譯期決定。

max_locals的單位是Slot,Slot是虛擬機器為區域性變數分配記憶體所使用的最小單位。對於長度不超過32位的資料型別,每個區域性變數佔用1個Slot。而double和long的資料型別長度為64位,需要佔用兩個Slot。

code[]陣列的位元組數(code_length)

型別:u4
位元組地址:000000FF~00000102
值:0x00000005

位元組碼指令(code)

型別:u1
長度/位元組數:5
位元組地址:00000103~00000107

image

其中,第0、1、4位元組為位元組碼指令,第2、3位元組為引數索引。

常量池

image

例項初始化方法位元組碼指令資訊

image

其中,初始化方法是沒有引數的,但args_size為1。這其實是因為對於非static方法,編譯器預設會將指向當前物件的this作為方法的第一個引數,以便在呼叫方法的時候使用。

異常表長度(exception_table_length)

型別:u2
位元組地址:00000108~00000109
值:0x0000

說明沒有異常表資訊。

異常表(exception_table)

屬性計數器(attributes_count)

型別:u2
位元組地址:0000010A~0000010B
值:0x0002

說明該欄位有2個屬性。

第1個方法Code屬性的第1個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:0000010C~0000010D
值:0x000C

對應常量池中的第12項常量,值為LineNumberTable,即位元組碼與原始碼的行號資訊。

LineNumberTable屬性值的長度(attribute_length)

型別:u4
位元組地址:0000010E~00000111
值:0x00000006

LineNumberTable行號表的長度(line_number_table_length)

型別:u2
位元組地址:00000112~00000113
值:0x0001

位元組碼與原始碼行號(位元組地址:00000114~00000117)

image
image

第1個方法Code屬性的第2個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:00000118~00000119
值:0x000D

對應常量池中的第13項常量,值為LocalVariableTable,即方法的本地變數表資訊。

LocalVariableTable屬性值的長度(attribute_length)

型別:u4
位元組地址:0000011A~0000011D
值:0x0000000C

將0x0000000C轉換為十進位制,計算得到12。

LocalVariableTable區域性變數表的長度(local_variable_table_length)

型別:u2
位元組地址:0000011E~0000011F
值:0x0001

LocalVariableTable第1個區域性變數(位元組地址:00000120~00000129)

image

start_pc和length兩者結合起來就是這個區域性變數在位元組碼之中的作用域範圍。

也就是說,這個區域性變數為this,型別為chapter6/TestClass,存放在區域性變數表的第0個Slot,作用域為code[0]~code[4]。

image

第1個方法對應的位元組內容

image

第2個方法

訪問標誌(access_flags)

型別:u2
位元組地址:0000012A~0000012B
值:0x0001

查表得到對應的訪問標誌為ACC_PUBLIC。

名稱索引(name_index)

型別:u2
位元組地址:0000012C~0000012D
值:0x0010

對應常量池中的第16項常量,值為inc,正是我們定義的例項方法名。

描述符(descriptor_index)

型別:u2
位元組地址:0000012E~0000012F
值:0x0011

對應常量池中的第17項常量,值為()I,說明該方法無引數,返回型別為int。

image

以上3項,說明該方法定義為public int inc()。

屬性計數器(attributes_count)

型別:u2
位元組地址:00000130~00000131
值:0x0001

說明該欄位有1個屬性。

第1個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:00000132~00000133
值:0x0009

對應常量池中的第9項常量,值為Code。

Code屬性值的長度(attribute_length)

型別:u4
位元組地址:00000134~00000137
值:0x00000031

將0x00000031轉換為十進位制,計算得到49。

Code運算元棧的最大深度(max_stack)

型別:u2
位元組地址:00000138~00000139
值:0x0002

即最大深度為2。

Code區域性變數的個數(max_locals)

型別:u2
位元組地址:0000013A~0000013B
值:0x0001

即區域性變數的個數為1。

code[]陣列的位元組數(code_length)

型別:u4
位元組地址:0000013C~0000013F
值:0x00000007

Code位元組碼指令(code)

型別:u1
長度/位元組數:7
位元組地址:00000140~00000146

image

其中,第0、1、4、5、6位元組為位元組碼指令,第2、3位元組為引數索引。

常量池

image

例項初始化方法位元組碼指令資訊

image

Code異常表長度(exception_table_length)

型別:u2
位元組地址:00000147~00000148
值:0x0000

說明沒有異常表資訊。

Code異常表(exception_table)

Code屬性計數器(attributes_count)

型別:u2
位元組地址:00000149~0000014A
值:0x0002

說明該欄位有2個屬性。

第2個方法Code屬性的第1個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:0000014B~0000014C
值:0x000C

對應常量池中的第12項常量,值為LineNumberTable。

值為LineNumberTable屬性值的長度(attribute_length)

型別:u4
位元組地址:0000014D~00000150
值:0x00000006

值為LineNumberTable行號表的長度(line_number_table_length)

型別:u2
位元組地址:00000151~00000152
值:0x0001

位元組碼與原始碼行號(位元組地址:00000153~00000156)

image
image

第2個方法Code屬性的第2個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:00000157~00000158
值:0x000D

對應常量池中的第13項常量,值為LocalVariableTable。

LocalVariableTable屬性值的長度(attribute_length)

型別:u4
位元組地址:00000159~0000015C
值:0x0000000C

將0x0000000C轉換為十進位制,計算得到12。

LocalVariableTable區域性變數表的長度(local_variable_table_length)

型別:u2
位元組地址:0000015D~0000015E
值:0x0001

LocalVariableTable第1個區域性變數(位元組地址:0000015F~00000168)

image

start_pc和length兩者結合起來就是這個區域性變數在位元組碼之中的作用域範圍。

也就是說,這個區域性變數為this,型別為chapter6/TestClass,存放在區域性變數表的第0個Slot,作用域為code[0]~code[6]。

image

第2個方法對應的位元組內容

image

類的屬性計數器(attributes_count)

型別:u2
位元組地址:00000169~0000016A
值:0x0001

說明該類有1個屬性。

第1個屬性

名稱索引(attribute_name_index)

型別:u2
位元組地址:0000016B~0000016C
值:0x0014

對應常量池中的第12項常量,值為SourceFile,即class檔案的Java原始檔名稱。

屬性值的長度(attribute_length)

型別:u4
位元組地址:0000016D~00000170
值:0x00000002

類的原始檔名稱索引(sourcefile_index)

型別:u2
位元組地址:00000171~00000172
值:0x0015

對應常量池中的第21項常量,值為TestClass.java。

image

位元組碼內容

image

參考

《Java虛擬機器規範》(Java SE 8版)

《深入理解Java虛擬機器 JVM高階特性與最佳實踐》

個人公眾號

更多文章,請關注公眾號:二進位制之路

二進位制之路

相關文章