本篇我們繼續分析Class檔案結構的方法及屬性部分內容,上節內容回顧請檢視:
Class檔案格式資訊
繼續上節例項程式碼
package chapter6;
public class TestClass {
private int m;
public int inc() {
return m + 1;
}
}
複製程式碼
使用JDK1.8編譯成class檔案,然後通過WinHex開啟
方法
上節我們分析到欄位部分,欄位的完整地址範圍: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個屬性。
屬性的通用格式如下:
第1個屬性
名稱索引(attribute_name_index)
型別:u2
位元組地址:000000F5~000000F6
值:0x0009
對應常量池中的第9項常量,值為Code。
屬性值的長度(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
其中,第0、1、4位元組為位元組碼指令,第2、3位元組為引數索引。
常量池
例項初始化方法位元組碼指令資訊
其中,初始化方法是沒有引數的,但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)
第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)
start_pc和length兩者結合起來就是這個區域性變數在位元組碼之中的作用域範圍。
也就是說,這個區域性變數為this,型別為chapter6/TestClass,存放在區域性變數表的第0個Slot,作用域為code[0]~code[4]。
第1個方法對應的位元組內容
第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。
以上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
其中,第0、1、4、5、6位元組為位元組碼指令,第2、3位元組為引數索引。
常量池
例項初始化方法位元組碼指令資訊
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)
第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)
start_pc和length兩者結合起來就是這個區域性變數在位元組碼之中的作用域範圍。
也就是說,這個區域性變數為this,型別為chapter6/TestClass,存放在區域性變數表的第0個Slot,作用域為code[0]~code[6]。
第2個方法對應的位元組內容
類的屬性計數器(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。
位元組碼內容
參考
《Java虛擬機器規範》(Java SE 8版)
《深入理解Java虛擬機器 JVM高階特性與最佳實踐》
個人公眾號
更多文章,請關注公眾號:二進位制之路