深入理解JVM(四)Class類的文件結構

1.Class文件的定義

Class文件時一組以8位字節為基礎單位的二進制流,當遇到需要占用8位字節以上空間的數據項時,則會按照高位在前的方式分割成若干個*位字節進行存儲。Class文件格式采用一種類似C語言結構體的偽結構來存儲數據,這種偽結構中只有兩種數據類型:無符號數和表。

1.1.無符號數

無符號數屬于基本的數據類型,根據這些值長度的不同分為:u1、u2、u4、u8,分別代表1字節的無符號數、2字節的無符號數、4字節的無符號數、8字節的無符號數。無符號數可以用來描述數字、索引引用、數量值或者按照UTF-8編碼構成字符串值。

1.2.表

表示由多個無符號數或者其他表作為數據項構成的復合數據類型,所有表都習慣地以"_info結尾"。表用于描述有層次關系的復合結構的數據,整個Class文件本質上就是一張表,它由表6-1所示的數據項構成。

2.Class文件的構成

2.1.魔數

class文件的頭4個字節稱為魔數,它的唯一作用是確定這個文件能否為一個能被虛擬機接受的Class文件。

魔數的作用就相當于文件后綴名,只不過后綴名容易被修改,不安全,因此在class文件中標示文件類型比較合適。

class文件的魔數是用16進制表示的“CAFEBABE”,非常具有浪漫主義色彩,誰說程序員的情商都很低!

2.2.版本號

緊接著魔數的四個字節是class文件的此版本號和主版本號。 隨著Java的發展, class文件的格式也會做相應的變動。 版本號標志著class文件在什么時候, 加入或改變了哪些特性。 舉例來說, 不同版本的javac編譯器編譯的class文件, 版本號可能不同, 而不同版本的JVM能識別的class文件的版本號也可能不同, 一般情況下, 高版本的JVM能識別低版本的javac編譯器編譯的class文件, 而低版本的JVM不能識別高版本的javac編譯器編譯的class文件。 如果使用低版本的JVM執行高版本的class文件,JVM會拋出java.lang.UnsupportedClassVersionError 。

2.3.常量池

2.3.1. 什么是常量池?

緊接著版本號之后的就是常量池。常量池中存放兩種類型的常量:字面值常量和符號引用。

字面值常量即我們在程序中定義的字符串、被final修飾的值。

符號引用就是我們定義的各種名字:類和接口的全限定名、字段的名字 和 描述符、方法的名字 和 描述符。

2.3.2 常量池的特點

常量池長度不固定

常量池的大小是不固定的,因此常量池開頭放置一個u2類型的無符號數,用來存儲當前常量池的容量。JVM根據這個值就知道常量池的頭尾來。

注:這個值是從1開始的,若為5表示池中有4個常量。

常量池中的常量由而為表來表示

常量池開頭有個常量池容量計數器,接下來就全是一個個常量了,只不過常量都是由一張張二維表構成,除了記錄常量的值以外,還記錄當前常量的相關信息。

常量池是class文件的資源倉庫

常量池是與本class中其它部分關聯最多的部分

常量池是class文件中空間占用最大的部分之一

2.3.3常量池中常量的特點

剛才介紹了,常量池中的常量大體上分為:字面值常量 和 符號引用。在此基礎上,根據常量的數據類型不同,又可以被細分為14種常量類型。這14種常量類型都有各自的二維表示結構。每種常量類型的頭1個字節都是tag,用于表示當前常量屬于14種類型中的哪一個。

以CONSTANT_Class_info常量為例,它的二維表示結構如下:

CONSTANT_Class_info表:

類型名稱數量

u1tag1

u2name_index1

tag表示當前常量的類型(當前常量為CONSTANT_Class_info,因此tag的值應為7,表示一個類或接口的全限定名);

name_index表示這個類或接口全限定名的位置。它的值表示指向常量池的第幾個常量。它會指向一個CONSTANT_Utf8_info類型的常量,它的二維表結構如下:

CONSTANT_Utf8_info表:

類型名稱數量

u1tag1

u2length1

u1byteslength

CONSTANT_Utf8_info表示字符串常量;

tag表示當前常量的類型,這里應該是1;

length表示這個字符串的長度;

bytes為這個字符串的內容(采用縮略的UTF8編碼)

問:為什么Java中定義的類、變量名字必須小于64K?

類、接口、變量等名字都屬于符號引用,它們都存儲在常量池中。而不管哪種符號引用,它們的名字都由CONSTANT_Utf8_info類型的常量表示,這種類型的常量使用u2存儲字符串的長度。由于2字節最多能表示65535個數,因此這些名字的最大長度最多只能是64K。

問:什么是UTF-8編碼?什么是縮略UTF-8編碼?

前者每個字符使用3個字節表示,而后者把128個ASKII碼用1字節表示,某些字符用2字節表示,某些字符用3字節表示。

2.4.訪問標志

在常量池之后是2字節的訪問標志。訪問標志是用來表示這個class文件是類還是接口、是否被public修飾、是否被abstract修飾、是否被final修飾等。

由于這些標志都由是/否表示,因此可以用0/1表示。

訪問標志為2字節,可以表示16位標志,但JVM目前只定義了8種,未定義的標志位一律為0.

2.5.類索引、父類索引與接口索引集合

類索引(this_class) 和父類索引(super class) 都是一個u2類型的數據,而接口索引(interfaces) 是一組u2類型的數據的集合,Class 文件中由這三項數據來確定這個類的承關系。類索引用于確定這個類的全限定名,父類索引用于確定這個類的父類的全限定名,由于Java 語言不允許多重繼承,所以父類索引只有一個,除了java.lang.Object 之外,所的Java 類都有父類,因此除了java lang.Object 外,所有Java 類的父類索引都不為0.接口索引集合就用來描述這個類實現了哪些接口,這些被實現的接口將按implements語句(如果這個類本身是一個接口,則應當是extends語句) 后的接口順序從左到右排列在接口索集合中。

它們按照順序依次排列,類索引和父類索引各自使用一個u2類型的無符號常量,這個常量指向CONSTANT_Class_info類型的常量,該常量的bytes字段記錄了本類、父類的全限定名。

接口索引集合,入口的第一項-u2類型的數據為接口計數器,表示索引表的容量。如果該類沒有實現任何接口,則該計數器值為0,后面接口的索引表不再占用任何字節。

2.6.字段表集合

字段表用于描述接口或者類中聲明的變量。字段包括類及變量以及實例及變量,但不包括在方法內部聲明的局部變量。

每一個字段表只表示一個成員變量,本類中所有的成員變量構成了字段表集合。

2.6.2 字段表結構的定義

類型? ?????????????????????????? 名稱??????????????????????? 數量

u2 ? ? ? ? ? ? ? ? ? ? ? ? access_flags??????? ? ? ? ? ? ? ? 1

u2? ? ? ?????????????????? name_index???????? ? ? ? ???????? 1

u2? ? ? ?????????????????? descriptor_index?? ? ? ? ? ? ? ?? 1

u2???????????????????????? attributes_count?????????????????? 1

attribute_info???????? attributes????????????? attributes_count

access_flags

字段的訪問標志。在Java中,每個成員變量都有一系列的修飾符,和上述class文件的訪問標志的作用一樣,只不過成員變量的訪問標志與類的訪問標志稍有區別。

name_index

本字段名字的索引。指向一個CONSTANT_Class_info類型的常量,這里面存儲了本字段的名字等信息。

descriptor_index

描述符。用于描述本字段在Java中的數據類型等信息(下面詳細介紹)

attributes_count

屬性表集合的長度。

attributes

屬性表集合。到descriptor_index為止是字段表的固定信息,光有上述信息可能無法完整地描述一個字段,因此用屬性表集合來存放額外的信息,比如一個字段的值。(下面會詳細介紹)

2.6.3 什么是描述符

成員變量(包括靜態成員變量和實例變量) 和 方法都有各自的描述符。

對于字段而言,描述符用于描述字段的數據類型;

對于方法而言,描述符用于描述字段的數據類型、參數列表、返回值。

在描述符中,基本數據類型用大寫字母表示,對象類型用“L對象類型的全限定名”表示,數組用“[數組類型的全限定名”表示。

描述方法時,將參數根據上述規則放在()中,()右側按照上述方法放置返回值。而且,參數之間無需任何符號。

2.6.4 字段表需要注意的點

一個class文件的字段表集合中不能出現從父類/接口繼承而來字段;

一個class文件的字段表集合中可能會出現程序猿沒有定義的字段

如編譯器會自動地在內部類的class文件的字段表集合中添加外部類對象的成員變量,供內部類訪問外部類。

Java中只要兩個字段名字相同就無法通過編譯。但在JVM規范中,允許兩個字段的名字相同但描述符不同的情況,并且認為它們是兩個不同的字段。

Class文件的構成

2.7:方法表的集合

在class文件中,所有的方法以二維表的形式存儲,每張表來表示一個函數,一個類中的所有方法構成方法表的集合。

方法表的結構和字段表的結構一致,只不過訪問標志和屬性表集合的可選項有所不同。

類型名稱數量

u2access_flags1

u2name_index1

u2descriptor_index1

u2attributes_count1

attribute_infoattributesattributes_count

方法表的屬性表集合中有一張Code屬性表,用于存儲當前方法經編譯器編譯過后的字節碼指令。

方法表集合的注意點

如果本class沒有重寫父類的方法,那么本class文件的方法表集合中是不會出現父類/父接口的方法表;

本class的方法表集合可能出現程序猿沒有定義的方法

編譯器在編譯時會在class文件的方法表集合中加入類構造器和實例構造器。

重載一個方法需要有相同的簡單名稱和不同的特征簽名。JVM的特征簽名和Java的特征簽名有所不同:

Java特征簽名:方法參數在常量池中的字段符號引用的集合

JVM特征簽名:方法參數+返回值

2.8:屬性表的集合

在Class文件,字段表,方法表中都可以攜帶自己的屬性表集合,以用于描述某些場景專有的信息。與Class文件中其它的數據項目要求的順序、長 度和內容不同,屬性表集合的限制稍微寬松一些,不再要求各個屬性表具有嚴格的順序,并且只要不與已有的屬性名重復,任何人實現的編譯器都可以向屬性表中寫入自己定義的屬性信息,Java虛擬機運行時會忽略掉它不認識的屬性。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380