Class 文件中的字段表、方法表與屬性表
1. 前言
本節內容主要是介紹 Class 文件結構中的字段表、方法表與屬性表。從本節標題的描述中,我們只看到了這 3 種表結構,但實際上本節會講解 6 種結構,因為每一種表結構,都需要有計數器進行計數。本節主要知識點如下:
- 字段表計數器和字段表的定義及意義,以及結構示意圖,為本節重點內容之一;
- 方法表計數器和方法表的定義及意義,以及結構示意圖,為本節重點內容之一;
- 屬性表計數器和屬性表的定義及意義,以及結構示意圖,為本節次重點內容,由于JVM 對屬性表沒有特別規范的限制,此處了解其定義及結構即可。
本節所講解的內容,是Class 文件結構的最后部分,學習完本節課程后,會對 Class 文件結構有一個整體的認識,并且每一部分的結構順序與課程中講解的順序完全一樣,把所有的示意圖進行拼接,就能夠形成一個完成的 Class 文件結構示意圖。
2. 字段表計數器和字段表
上節課程拋出了問題,接口索引集合后邊緊跟的結構是什么?這里我們來進行解答,后邊緊跟的是字段表計數器,字段表計數器后邊緊跟的是字段表。
定義:字段表計數器(fields_count)與字段表不可分割,這里我們對兩部分結構一起講解。
- 字段表計數器(fields_count):記錄字段表中字段的數量,為無符號數類型。
- 字段表(fields):字段表(fields)用于描述接口或者類中聲明的變量。字段(field)包括類級變量(即靜態變量)以及實例變量(即:非靜態變量),但不包括在方法內部聲明的局部變量。字段表為表類型結構。
Tips:這里請學習者特別關注下字段表定義介紹中的最后兩句話:“字段(field)包括類級變量(即靜態變量)以及實例變量(即:非靜態變量),但不包括在方法內部聲明的局部變量。“ 簡單的總結這句話的意思是字段表中存儲的是全局標量,不存儲局部變量。
字段表計數器無符號數結構示意圖:與其他計數器一樣,字段表計數器(fields_count)是一個無符號數結構類型的數據,u2 大小。
字段表-表結構類型示意圖:字段表是一個表結構的類型數據,回憶下我們接觸到的第一個 Class 文件的表結構類型數據為常量池。這里我們來看下字段表的表結構示意圖。
前文提到過,字段(field)包括類級變量(即靜態變量)以及實例變量(即:非靜態變量),上圖所示的一個 field_info 就代表了一個變量。為了表示一個變量,需要知道這個變量的修飾符,如 public,還需要知道這個變量的變量名稱,因此一個 field_info 中存儲了很多特征值,所有的特征值綜合起來就完整的描述了一個變量。
3. 方法表計數器與方法表
字段表后邊緊跟的是方法表計數器,方法表計數器后邊緊跟的是方法表。
定義:方法表計數器(methods_count)與方法表不可分割,這里我們對兩部分結構一起講解。
- 方法表計數器(methods_count):記錄方法表中字段的數量,為無符號數類型。
- 方法表(methods):存儲了當前類或者當前接口中的 public 方法,protected 方法,default 方法,private 方法等。方法表為表結構類型。
Tips:Class文件是通過Java文件編譯而來的,如果文件中有方法,就會將方法的信息存儲到方法表,并通過方法表計數器進行方法的計數。
方法表計數器無符號數結構示意圖:與其他計數器一樣,方法表計數器(methods_count)是一個無符號數結構類型的數據,u2 大小。
方法表-表結構類型示意圖:方法表是一個表結構的類型數據,與前文所講解的字段表結構一樣。
一個method_info中會存儲很多方法的特征值,我們通過如下示例方法進行舉例:
public String get(String name) {
return "";
}
對于get 方法,method_info 中會存儲如下信息:
- 方法的修飾符 public:還記的我們上節所講述的 access_flag 嗎?access_flag 對應表中有一個 ACC_PUBLIC 就代表了 public 修飾符,他對應的值為
0x0001
,此處的標記也需要使用到這個表。都是通用的哦; - 方法名稱:get 方法;
- 方法的參數:String name;
- 方法的返回值類型: String 類型的返回值。
通過如上方法特征值的共同修飾,完成了一個 method_info 的存儲,也就完成了一個方法的存儲。
4.屬性表計數器與屬性表
方法表后邊緊跟的是屬性表計數器,屬性表計數器后邊緊跟的結構為屬性表。至此,Class 文件的全部結構就講解完了?;仡欀暗闹R,Class 文件結構是以魔數開頭,以屬性表結尾的。
定義:屬性表計數器(attributes_count)與屬性表不可分割,這里我們對兩部分結構一起講解。
- 屬性表計數器(attributes_count):記錄屬性表中屬性的數量,為無符號數類型。
- 屬性表(attributes):屬性表(attributes)與 Class 文件中其他的數據項目要求嚴格的順序、長度和內容不同,屬性表集合的限制稍微寬松一些,不再要求各個屬性表具有嚴格的順序,并且只要不與已有屬性名重復,任何人實現的編譯器都可以向屬性表中寫入自己定義的屬性信息,Java 虛擬機運行時會忽略掉它不能識別的屬性。
Tips:學習者對屬性這一概念并不陌生了,這里不多加贅述,但是我們重點要關注下屬性表的兩大特點:一個是限制寬松,無順序長度要求;一個是開發者可以自己向屬性表中添加不重復的屬性。言外之意是屬性表作為 Class 文件的一個結構,是非常靈活的,且沒有明確的長度大小規定。此部分知識我們稍作了解即可。
屬性表計數器無符號數結構示意圖:與其他計數器一樣,屬性表計數器(attributes_count)是一個無符號數結構類型的數據,u2 大小。
屬性表-表結構類型示意圖:屬性表也是一個表結構類型,與字段表、方法表結構類似,但是屬性表沒有固定的長度和順序限制,此處我們了解下其結構即可。
5. 小結
本節講解了 Class 文件結構中最后的幾種結構,分別是字段表計數器,字段表,方法表計數器,方法表,屬性表計數器,屬性表。其中字段表與方法表為本節重點內容,屬性表部分視為次重點,僅做了解即可。
至此,我們的 Class 文件結構就講解完了,我們回顧下 Class 文件的整體結構為:魔數->次版本號->主版本號->常量池計數器->常量池->類索引->父類索引->接口索引計數器->接口索引集合->字段表計數器->字段表->方法表計數器->方法表->屬性表計數器->屬性表。
學習者需要認真學習 Class 文件的數據結構,掌握整體結構以及細節知識點。