Class文件解讀(六)

接上篇:http://www.javashuo.com/article/p-xdetuxcw-ky.htmljava

屬性表this

       屬性表(attribute_info)在前面的講解之中已經出現過不少次,在Class文件中、字段表、方法表均可以攜帶本身的屬性表集合,以用於描述某些特定的場景信息。spa

       與Class文件中其餘的數據項目要求嚴格的順序、長度和內容不一樣,屬性表集合的限制稍微寬鬆了一些,再也不要求各個屬性表具備嚴格順序,任何人實現的編譯器均可以向Class文件中寫入本身定義的屬性信息,只要不與已有的屬性名重複,Java虛擬機運行時會忽略掉它不認識的屬性,從這一點看,屬性表看似放開的限制,但這種放開是沒有意義的,至少在目前規則下是這樣的。Java虛擬機爲確保可以正確地解析Class文件,預約義了以下屬性:.net

虛擬機規範預約義的屬性調試

屬性名稱 使用位置 含義
Code 方法表 Java代碼編譯成的字節碼指令
ConstantValue 字段表 final關鍵字定義的常量(同時須要被static修飾)
Deprecated 類、方法表、字段表 被聲明爲deprecated的方法和字段
Exceptions 方法表 方法拋出的異常
EnclosingMethod 類文件 僅當一個類爲局部類或者匿名類時才能擁有這個屬性,這個屬性用於標識這個類所在的外圍方法
InnerClass 類文件 內部類列表
LineNumberTable Code屬性 Java源代碼的行號與字節碼指令的對應關係
LocalVariableTable Code屬性 方法的局部變量描述
StackMapTable Code屬性 JDK1.6中新增的屬性,供新的類型檢查驗證器(Type Checker)檢查和處理目標方法的局部變量和操做數棧所須要的類型是否匹配
Signature 類、方法表、字段表 JDK1.5中新增的屬性,這個屬性用於支持泛型狀況下的方法簽名,在Java語言中,任何類、接口、初始化方法或成員的泛型簽名若是包含了類型變量(Type Variables)或參數化類型(Parameterized Types),則Signature屬性會爲它記錄泛型簽名信息。因爲Java的泛型採用擦除法實現,在爲了不類型信息被擦除後致使簽名混亂,須要這個屬性記錄泛型中的相關信息。
SourceFile 類文件 記錄源文件名稱
SourceDebugExtension 類文件 JDK1.6中新增的屬性,SourceDebugExtension屬性用於存儲額外的調試信息。譬如在進行JSP文件調試時,沒法經過Java堆棧來定位到JSP文件的行號,JSR-45規範爲這些非Java語言編寫,卻須要編譯成字節碼並運行在Java虛擬機中的程序提供了一個進行調試的標準機制,使用SourceDebugExtension屬性就能夠用於存儲這個標準所新加入的調試信息
Synthetic 類、方法表、字段表 標識方法或字段爲編譯器自動生成的
LocalVariableTypeTable JDK1.5中新增的屬性,它使用特徵簽名代替描述符,是爲了引入泛型語法以後能描述泛型參數化類型而添加
RuntimeVisableAnnotations 類、方法表、字段表 JDK1.5中新增的屬性,爲動態註解提供支持。RuntimeVisableAnnotations屬性用於指明哪些註解時運行時(實際上運行時就是進行反射調用)可見的。
RuntimeInvisableAnnotations 類、方法表、字段表 JDK1.5中新增的屬性,與RuntimeVisableAnnotations屬性做用恰好相反,用於指明哪些註解是運行時不可見的。
RuntimeVisableParameterAnnotations 方法表 JDK1.5中新增的屬性,做用與RuntimeVisableAnnotations相似,只不過做用對象爲方法參數
RuntimeInvisableParameterAnnotations 方法表 JDK1.5中新增的屬性,做用與RuntimeInvisableAnnotations屬性相似,只不過做用對象爲方法參數
AnnotationDefault 方法表 JDK1.5中的新增屬性,用於記錄註解類元素的默認值
BootstrapMethod 類文件 JDK1.7中新增的屬性,用於保存invokedynamic指令引用的引導方法限定符

        對於每一個屬性,它的名稱須要從常量池中引用一個CONSTANT_Utf8_info類型的常量來表示而屬性值的結構則徹底是自定義的,只須要經過一個u4的長度屬性去說明屬性值所佔用的位數便可,一個符合規則的屬性表須要知足下表所定義的結構:code

                                                                            屬性表結構對象

類型 名稱 數量
u2 attribute_name_index 1
u4 attribute_length 1
u1 info attribute_length

Code屬性blog

       Class文件中屬性表中最重要的屬性類型,沒有之一。索引

       Java程序方法體中的代碼通過javac編譯器處理後,最終變爲字節碼指令存儲在Code屬性內。Code屬性出如今方法表的屬性集合之中,但並非全部的方法表都必須存在這個屬性,譬如接口或者抽象類中的方法就不存在Code屬性,若是方法表有Code屬性存在,那麼它的結構以下表:接口

                                                                    Code屬性表的結構

類型 名稱 數量
u2 attribute_name_index 1
u4 attribute_length 1
u2 max_stack 1
u2 max_locals 1
u4 code_length 1
u1 code code_length
u2 exception_table_length 1
exception_info exception_table exception_table_length
u2 attributes_count 1
attribute_info attributes attributes_count

        attribute_name_index是一項指向CONSTANT_Utf8_info型常量的索引,常量值固定爲"Code",它表明了該屬性的屬性名稱,attribute_length指示了屬性值的長度,因爲屬性名稱索引與屬性長度一共6字節,因此屬性值的長度固定爲整個屬性表長度減去6個字節。

        max_stack表明了操做數棧(Operand Stacks)深度的最大值。在方法執行的任意時刻,操做數棧都不會超過這個深度。虛擬機運行的時候須要根據這個值來分配棧幀(Stack Frame)中的操做棧深度。

        max_locals表明了局部變量表所需的存儲空間。在這裏,max_local的單位是Slot,Slot是虛擬機爲局部變量分配內存所使用的最小單位。對於byte、char、float、int、short、boolean和returnAddress等長度不超過32位的數據類型,每一個局部變量佔用1個Slot,而double和long這兩種64位的數據類型則須要兩個Slot來存放。方法參數(包括實例方法中的隱藏參數"this")、顯式異常處理器的參數(Exception Handler Paramter,就是try-catch語句中catch塊所定義的異常)、方法體中定義的局部變量都須要使用局部變量表來存放,另外,並非在方法中用到了多少個局部變量,就把這些局部變量所佔Slot之和座位max_locals的值,緣由是局部變量表中的Slot能夠重用,當代碼執行超出一個局部變量的做用域時,這個局部變量所佔用的Slot能夠被其它局部變量所使用,Javac編譯器會根據變量的做用域來分配Slot給各個變量使用,而後計算出max_locals的大小。

       code_length和code用來存儲Java源程序編譯後生成的字節碼指令。code_length表明字節碼長度,code是用於存儲字節碼指令的一系列字節流。即然叫字節碼指令,那麼每一個指令就是一個u1類型的單字節,當虛擬機讀取到code中的一個字節碼時,就能夠對應找出這個字節碼的是什麼指令,而且能夠知道這條指令後面是否須要跟隨參數,以及參數應當如何理解。咱們知道一個u1數據類型的取值範圍爲Ox00~OxFF,對應十進制的0~255,也就是一共能夠表達256條指令。

        Code屬性是Class文件中最重要的一個屬性,若是把一個Java程序中的信息分爲代碼(Code,方法體裏面的Java代碼)和元數據(Metadata,包括類、字段、方法定義以及其餘信息)兩部分,那麼在整個Class文件中,Code屬性用於描述代碼,全部其餘數據項目都用於描述元數據。

        在字節碼指令以後的是這個方法的顯式異常處理表(下文簡稱異常表)集合,異常表對與Code屬性來講並非必須存在的。異常表的格式以下表所示,它包含4個字段,這些字段的含義爲:若是當字節碼在第start_pc行到end_pc行之間(不含第end_pc行)出現了類型爲catch_type或者其子類的異常(catch_type爲指向一個CONSTANT_Class_info型常量的索引),則轉到第handler_pc行繼續處理。當catch_type的值爲0時,表明任意異常都須要轉向到handler_pc處進行處理。

                                                                            屬性表結構 

類型 名稱 數量
u2 start_pc 1
u2 end_pc 1
u2 handler_pc 1
u2 catch_type 1

       異常表其實是Java代碼的一部分,編譯器使用異常表而不是簡單的跳轉命令來實現Java異常激finally處理機制。

相關文章
相關標籤/搜索