LineNumberTable 屬性表存放方法的行號信息 ;屬於調試信息,不是運行時必需的。在使用javac編譯器編譯Java程式時,預設會在class文件中生成這些信息。可以使用javac提供的-g:none選項來關閉該信息的生成 ...
一、Methods 方法位元組碼結構
Methods 位元組碼結構:
Methods num:占兩byte,Methods 的具體記憶體占n個byte
方法中每個屬性都是Attribute_info,Attribute_info的結構:
1、attribute_name_index:屬性名的索引
2、attribute_length:表示attribute所包含的位元組數,不包含attribute_name_index和attribute_length欄位
3、max_stack:表示這個方法運行的任何時刻所能到達的操作數棧的最大深度。
4、max_locals:表示方法執行期間創建的局部變數的數目,包含用來表示傳入的參數的局部變數。
5、code_length:表示該方法所包含的位元組碼的位元組數以及具體的指令碼,具體位元組碼即是該方法被調用時,虛擬機執行的位元組碼
6、code[code_length]:虛擬機運行時具體的位元組
7、exception_table_length:異常表的長度
8、exception_table:
- 這裡存放的是處理異常的信息每個exception_table表項由start_pc, end_pc, handler_pc, catch_type組成;
- start_pc 和end_pc表示在code數組中的從start_pc到end_pc處(包含start_pc,不包含end_pc)的指令拋出的異常會由這個表項來處理。
- handler_pc表示處理異常的代碼的開始處;
- catch_type表示會被處理的異常類型,它指向常量池裡的一個異常類。當catch_type為0時,表示處理所有的異常
9、Attribute_count:
10、Attribute_info Attributes[Attribute_count]
二、Methods 位元組碼分析
上一節 JAVA位元組碼文件之第三篇(訪問標識) 我們分析到了 Fields(屬性)位元組碼 就是圖中紅色箭頭的位置。
1、Methods num(3) : 占兩個byte 00 03,即該類有三個方法。
第一個方法:
Access_Flags(1):占2個byte 00 01;根據 上一節JAVA位元組碼文件之第三篇(訪問標識) 可知
name_index(7):占 2個位元組 00 07;索引為7,對應常量池中的#7, 由<init>可知他是一個構造方法
descriptor_index(8):占兩個byte,00 08,對應常量池的#8,由()V可知這是一個無參數的(構造)方法
attribute_info結構
attributes_count(1):占兩個byte 00 01,表示該方法第一個屬性(這裡的屬性並不是我們常說的類的屬性,方法的參數,而是編譯器生成的屬性)
1、Attribute_name_index(9):方法的第一個屬性名字,占兩個byte,對應常量池中的#9,code就是該方法的第一個屬性
2、Attribute_length(0x38=56):占4個byte 00 00 00 38,表明該屬性code的長度是56個位元組。所以整個Attribute_info 對應位元組如下圖
3、max_stack(2):占2個byte 00 02 操作數棧的最大深度是2
4、max_locals(1):占兩個byte 00 01
5、code_length(10) :占四個位元組 00 00 00 0A ,
6、code[code_length]:占 code_length 個byte 即 10個byte ,2A B7 00 01 2A 04 B5 00 02 B1 ;表明該方法在執行時的具體指令;
這些十六進位指令怎麼與 圖片中的助記符關聯的,參考該 網站 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.aload_n
例如:aload_0=2A
invokespecial=B7 , 之後的 00 01是他的參數,指向常量池中的#1
父類的構造方法
iconst_1=4
putfield=B5 ,後兩個byte 是 參數 00 02,對應常量池的#2
就是給屬性賦值 即 int num=1
return = B1 ,構造方法返回void
7、exception_table_length(0): 占兩個byte 00 00 ,所以預設的構造器不拋出異常
8、exception_table_info:由於exception_table_length =0 ,所以該部分內容為空
9、Attribute_count (2): 占兩個byte 00 02 ,即構造器的Code屬性有兩個擴展屬性
10、Attribute_info[Attribute_count] : 00 0A ,0A=10 ,第一個擴展屬性的索引=10,即常量池的#10
11、LineNumberTable 分析
Attribute_length : 占4個byte,00 00 00 0A;0X0A=10,所以00 02 00 00 00 08 00 04 00 09 是LineNumberTable 的具體指令;
前兩個位元組 00 02 表示 有兩對映射關係,00 00 對應 00 08 ,08對應常量池的#8 ;00 04 對應 00 09 ,對應常量池的#9
12、第二個擴展屬性 00 0B,0x0B=11 ,對應常量池的#11
Attribute_length :占四個位元組 00 00 00 0C,對應的 LocalVariableTable 的內容是 12 個位元組 ,即 00 01 00 00 00 0A 00 0C 00 0D 00 00 。
局部變數的格式:00 01
開始位置 00 00
結束位置 00 0A(0A=10)
索引是 00
局部變數對應常量池的位置0C(C=12)
當前局部變數的描述00 0D ,對應常量池的#13
最後的00 00 是一個校驗符,沒有具體的邏輯含義。
至從第一個方法分析完畢。
三、LineNumberTable
LineNumberTable 屬性表存放方法的行號信息 ;屬於調試信息,不是運行時必需的。在使用javac編譯器編譯Java程式時,預設會在class文件中生成這些信息。可以使用javac提供的-g:none選項來關閉該信息的生成
四、LocalVariableTable:列出了所有棧幀中的局部變數
LineNumberTable