本文參考書籍:《深刻理解Java虛擬機》有興趣的同窗也能夠經過看書瞭解更多內容。
最近在讀這本書,順便作下知識整理。在瞭解了class文件結構後能夠更好的瞭解類的加載機制。若是對此內容已經瞭解的同窗能夠移步:類的加載機制。java
如需轉載請註明出處,class文件的結構 。linux
java語言的一句口號你們應該都很熟悉:"Write once, run anywhere." 那是由於Java虛擬機不與任何語言綁定,它只與「Class文件」這種特定的二進制文件格式所關聯。 Java虛擬機也不止支持java一種語言。數組
從上圖能夠看出多種語言經過編譯成*.class文件均可以在JVM上運行。 下面讓咱們瞭解一下class文件的結構。安全
注:(此文以JDK1.4爲主線講解)post
首先看一下class文件的基本概念:測試
class文件是一組以8位字節爲基礎單位的二進制流,各個數據項目嚴格按照順序節湊的排列在Class文件中,中間沒有添加任何分隔符,使得整個Class文件中從存儲的內容幾乎所有是程序運行時的必要數據,沒有任何空隙。當遇到須要佔用8位以上空間的數據項時,則會按照高位在前的方式分割爲若干個8位字節進行存儲。this
1,無符號數:屬於基本的數據類型,以u一、u二、u四、u8來分別表明一、二、四、8個字節的無符號數,無符號數能夠用來描述數字、索引引用、數量值、或者按照UTF-8編碼的字符串值。
2,表:由多個無符號數或者其餘表做爲數據項構成的複合數據類型,全部表都習慣性的以「info」結尾。Class文件本質上就是一張表。
下面是一張普通class文件的表,咱們能夠看下錶的大致結構和具體內容都有什麼。編碼
圖2中紅字標註後面會作具體分析。3d
每一個Class文件的前4個字節稱爲魔數(Magic Number),它的惟一做用是肯定這個文件是不是一個能被虛擬機接受的Class文件。使用魔數而不使用擴展名來驗證是出於安全考慮,由於擴展名能夠隨意改變。java語言魔數就是:CAFEBABE(十六進制數)。此 魔數也用於後面類加載中的驗證。cdn
Class第五、6個字節是次版本號,七、8個字節是主版本號。(主版本號就是咱們常說的JDK1.7或1.8,次版本號就是1.7後面的小版本號。)
常量池能夠理解爲Class文件的資源倉庫。 因爲常量池中常量的數量是不固定的,因此在常量池入口須要放置一項u2類型的數據,表明常量池容量計數值(constant_pool_count)。常量池索引從1開始。
如上圖6-3所示,魔數後是小版本號和大版本號,後面緊跟着就是常量池入口,入口前兩個字節表示了常量池中常量的個數。圖中都爲十六進制數,0x16就是十進制的22,而常量池計數都是從1開始,不是從0開始,因此這裏面表示常量池中索引範圍是1~21,而非0~21,因此常量池中共有21項常量。
常量池中主要存放兩大類常量:1,字面量。2,符號引用。
接近於Java語言層面的常量概念。如:字符串,final常量等。
屬於編譯原理方面概念,包括下面三類:
常量池中每一項常量都是一個表,在JDK1.7以前共有14種結構各不相同的表結構數據,1.7以後又額外增長了3種。 這14種表都有一個共同的特色,就是表開始的第一位是一個u1類型的標誌位(tag),表明當前這個常量屬於哪一種常量類型。
下面咱們來看下這些表的結構。
上面咱們已經說過第九個字節0x16是常量池入口,也是常量池中常量的數量,那麼緊接着就是常量池的第一項常量。請看下圖。
tag是標誌位,區分常量類型;name_index是一個索引,它指向常量池中一個CONSTANT_Utf8_info類型常量,此常量表明瞭這個類和接口的全限定名。圖4中第一個常量的tag爲0x07,咱們查看圖5中的表來肯定是哪一種常量類型。
常量池緊接着兩個字節表明訪問標誌(access_flags)。 訪問標誌:類或接口的層次信息,包括:這個Class是類仍是接口;是不是public;是否認義abstract;若是是類的話,是否聲明final等。圖10表示了訪問標誌具體表述的全部內容。
能夠查找圖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文件中由這三項數據來肯定類的繼承關係。
接下來就是字段表集合。
字段表(field_info):用於描述接口或者類中聲明的變量。
你們能夠想一下Java描述字段能夠包含哪些信息?
包括信息有:做用域(public、private、protected)、是否static、是否final、是否volatile、是否transient、字段數據類型(基本類型、對象、數組)、字段名稱。
理解了上面的字段表,方法表的結構和字段表相似。
看完此篇之後更容易理解:類的加載機制,若是有興趣的同窗能夠繼續閱讀。
歡迎若有問題歡迎留言。