Class文件結構

題外話:

本文參考書籍:《深刻理解Java虛擬機》有興趣的同窗也能夠經過看書瞭解更多內容。
最近在讀這本書,順便作下知識整理。在瞭解了class文件結構後能夠更好的瞭解類的加載機制。若是對此內容已經瞭解的同窗能夠移步:類的加載機制java

如需轉載請註明出處,class文件的結構linux

java語言的一句口號你們應該都很熟悉:"Write once, run anywhere." 那是由於Java虛擬機不與任何語言綁定,它只與「Class文件」這種特定的二進制文件格式所關聯。 Java虛擬機也不止支持java一種語言。數組

圖1

圖1 Class文件的結構

從上圖能夠看出多種語言經過編譯成*.class文件均可以在JVM上運行。 下面讓咱們瞭解一下class文件的結構。安全

Class類文件結構

注:(此文以JDK1.4爲主線講解)post

首先看一下class文件的基本概念測試

class文件是一組以8位字節爲基礎單位的二進制流,各個數據項目嚴格按照順序節湊的排列在Class文件中,中間沒有添加任何分隔符,使得整個Class文件中從存儲的內容幾乎所有是程序運行時的必要數據,沒有任何空隙。當遇到須要佔用8位以上空間的數據項時,則會按照高位在前的方式分割爲若干個8位字節進行存儲。this

Class文件結構中只有兩種數據類型:1,無符號數。2,表。

1,無符號數:屬於基本的數據類型,以u一、u二、u四、u8來分別表明一、二、四、8個字節的無符號數,無符號數能夠用來描述數字、索引引用、數量值、或者按照UTF-8編碼的字符串值。
2,:由多個無符號數或者其餘表做爲數據項構成的複合數據類型,全部表都習慣性的以「info」結尾。Class文件本質上就是一張表
下面是一張普通class文件的表,咱們能夠看下錶的大致結構和具體內容都有什麼。編碼

class文件結構

圖2 Class文件格式

圖2中紅字標註後面會作具體分析。3d

一,魔數和Class文件的版本

魔數

每一個Class文件的前4個字節稱爲魔數(Magic Number),它的惟一做用是肯定這個文件是不是一個能被虛擬機接受的Class文件。使用魔數而不使用擴展名來驗證是出於安全考慮,由於擴展名能夠隨意改變。java語言魔數就是:CAFEBABE(十六進制數)。此 魔數也用於後面類加載中的驗證。cdn

Class文件版本

Class第五、6個字節是次版本號,七、8個字節是主版本號。(主版本號就是咱們常說的JDK1.7或1.8,次版本號就是1.7後面的小版本號。)

二,常量池

常量池能夠理解爲Class文件的資源倉庫。 因爲常量池中常量的數量是不固定的,因此在常量池入口須要放置一項u2類型的數據,表明常量池容量計數值(constant_pool_count)。常量池索引從1開始。

圖3 常量池結構

如上圖6-3所示,魔數後是小版本號和大版本號,後面緊跟着就是常量池入口,入口前兩個字節表示了常量池中常量的個數。圖中都爲十六進制數,0x16就是十進制的22,而常量池計數都是從1開始,不是從0開始,因此這裏面表示常量池中索引範圍是1~21,而非0~21,因此常量池中共有21項常量。
常量池中主要存放兩大類常量:1,字面量。2,符號引用。

1,字面量

接近於Java語言層面的常量概念。如:字符串,final常量等。

2,符號引用

屬於編譯原理方面概念,包括下面三類:

(1)類和接口的全限定名
(2)字段的名稱和描述
(3)方法的名稱和描述

常量池中每一項常量都是一個表,在JDK1.7以前共有14種結構各不相同的表結構數據,1.7以後又額外增長了3種。 這14種表都有一個共同的特色,就是表開始的第一位是一個u1類型的標誌位(tag),表明當前這個常量屬於哪一種常量類型。
下面咱們來看下這些表的結構。
上面咱們已經說過第九個字節0x16是常量池入口,也是常量池中常量的數量,那麼緊接着就是常量池的第一項常量。請看下圖。

圖4 常量池結構

tag是標誌位,區分常量類型;name_index是一個索引,它指向常量池中一個CONSTANT_Utf8_info類型常量,此常量表明瞭這個類和接口的全限定名。圖4中第一個常量的tag爲0x07,咱們查看圖5中的表來肯定是哪一種常量類型。

圖5 常量池項目類型

從圖5中能夠看出0x07也就是十進制的7表明的類型是CONSTANT_Class_info,而後咱們在查詢圖6中CONSTANT_Class_info的表結構。

圖6 CONSTANT_Class_info型的常量結構

這裏name_index值爲0x0002,指向常量池第二項常量。由圖4能夠看出,第二項常量的tag是0x01,再查詢圖5可知,第二個常量是一個CONSTANT_Utf 8_info,咱們再來查詢CONSTANT_Utf 8_info型常量的結構。見圖7。

圖7 CONSTANT_Utf8_info型的常量結構


圖7中,0x01位tag位,表明CONSTANT_Utf8_info型的常量,0x001D即10進制的29,表明了字符串的長度爲29,緊接着後面括號中共29個字節,表明了29個字符,表示了類的全限定名。在圖8的右側你們也能夠看一下,類的全限定名被解析出來了,即"org/fenixsoft/clazz/TestClass",有興趣能夠數一下,我數過了是29個字符。[捂臉]

圖8 常量池第二項常量結構

以上是給你們舉了一些class文件中常量池結構的例子,以及如何分析那一部分對應常量池中的那些內容,下面就不一一舉例了。有興趣的同窗能夠查看一下官方的文檔。
圖8是常量池中14種常量項結構總表,在JDK1.7以前只有14種,你們能夠大概瞭解一下,常量池就介紹到這裏。

圖9 常量池中14種常量項結構總表

三,訪問標誌

常量池緊接着兩個字節表明訪問標誌(access_flags)。 訪問標誌:類或接口的層次信息,包括:這個Class是類仍是接口;是不是public;是否認義abstract;若是是類的話,是否聲明final等。圖10表示了訪問標誌具體表述的全部內容。

圖10 訪問標誌

圖11 測試類的訪問標誌

能夠查找圖10中的表測試類訪問標誌爲0x21就是圖10中ACC_PUBLIC和ACC_SUPER的結合,可見這個TestClass類就是一個普通的public的java類。
這種方式你們能夠聯想一下linux的權限碼,我感受很相似,例如:chmod 755 + 文件名,755中三位數字分表表示文件所屬用戶的權限、文件所屬組的權限、其餘用戶權限。4表明讀權限,2表明寫權限,1表明執行權限。755就是賦予文件全部者讀、寫、執行權限(4 + 2 + 1 = 7),賦予文件全部者的組讀、執行的權限(4 + 1 =5),賦予其餘用戶也是讀和執行的權限(4 + 1 = 5)。是否是與這個access_flags很是類似,用不多的字符表示多個屬性。

四,類索引、父類索引與接口索引集合

訪問標誌後接的下來就是類索引和父類索引,類索引和父類索引都是u2類型數據,接口索引集合是一組u2類型的數據集合。Class文件中由這三項數據來肯定類的繼承關係。

(1)類索引,類全限定名。

(2)父類全限定名。

(3)實現的接口。入口第一項是接口計數器,即表示索引表的容量。若是沒有實現接口,計數器值爲0,後面接口索引表就不佔用任何字節。

圖12 測試類類索引、父類索引、實現的接口

分析圖12,能夠看出圖11後access_flags(0x21)後就是類索引、父類索引、類實現的接口信息。從圖12能夠分析出,this_class(當前類)指向常量池中第一個常量,super_class(父類)指向常量池中第三項,而interfaces_count(實現的接口數)爲0,即這個類沒有實現任何接口。咱們再來看常量池圖,圖13。

圖13 常量池圖

剛纔在常量池的部分已經講過常量池的第一個常量是CONSTANT_Class_info表明類或接口的符號引用,第一項常量又指向第二項常量CONSTANT_Utf8_info,即當前類的全限定名,因此這個類的this_class就是"org/fenixsoft/clazz/TestClass",而由圖12看出super_class指向常量池中的第三項常量,從圖13得出常量池第三項常量(CONSTANT_Class_info)又指向常量池中第四項常量,第四項常量tag爲0x01,即CONSTANT_Class_info型,表明了super_class(父類)的全限定名,即"java/lang/Object",這個TestClass類沒有繼承任何類,因此父類爲Object,圖中也標記了this_class和super_class表明的字符串。

五,字段表集合

接下來就是字段表集合。
字段表(field_info):用於描述接口或者類中聲明的變量。
你們能夠想一下Java描述字段能夠包含哪些信息?
包括信息有:做用域(public、private、protected)、是否static、是否final、是否volatile、是否transient、字段數據類型(基本類型、對象、數組)、字段名稱。

圖14 字段表結構

圖15 字段訪問標誌(access_flags)

name_index和descriptor_index都是對常量池的引用。 name_index:字段的簡單名稱。例如:方法inc()和m字段,簡單名稱就是:inc和m。 descriptor_index:字段和方法的描述符,用來描述字段的數據類型、方法參數列表(包括數量、類型以及順序)和返回值,見圖16。

圖16 描述標誌符的含義

六,方法表集合

理解了上面的字段表,方法表的結構和字段表相似。

圖17 方法表結構

圖18 方法訪問標誌(access_flags)

class文件結構就先說到這裏,若有興趣的同窗能夠參考《深刻理解Java虛擬機》和《Java虛擬機規範》。

看完此篇之後更容易理解:類的加載機制,若是有興趣的同窗能夠繼續閱讀。

歡迎若有問題歡迎留言。

相關文章
相關標籤/搜索