通過對一個class文件的分析,基本理解了class文件結(jié)構(gòu),在這里最后再做一個總結(jié),梳理下class文件內(nèi)容。 兩種結(jié)構(gòu)class文件內(nèi)容如果泛化的區(qū)分可以分成兩種結(jié)構(gòu): 1、字節(jié)數(shù)據(jù):通過預(yù)先指定結(jié)構(gòu)的占用字節(jié)數(shù)來存儲基本的數(shù)據(jù)類型,比如class文件最開始的幾個字節(jié)按順序存儲了魔數(shù)、小版本、大版本,再比如字段結(jié)構(gòu)的訪問標(biāo)識符,都是通過提前確定了結(jié)構(gòu)所占用的字節(jié)數(shù),根據(jù)占用的字節(jié)來存儲數(shù)據(jù); 2、表:表是由字節(jié)數(shù)據(jù)和其他的表結(jié)構(gòu)組合而成,比如整個class文件就可以當(dāng)成一個表結(jié)構(gòu),它是由常量池數(shù)據(jù)這種基本結(jié)構(gòu)和常量池、方法結(jié)構(gòu)等表結(jié)構(gòu)組成; 表結(jié)構(gòu)還有一種特殊結(jié)構(gòu),可以看成一個數(shù)組結(jié)構(gòu),比如常量池結(jié)構(gòu)就是一種由多種常量池類型組成的數(shù)組結(jié)構(gòu),比如方法結(jié)構(gòu)也是一個數(shù)組結(jié)構(gòu),一個類中有多個方法,方法結(jié)構(gòu)就是多個方法組成的結(jié)構(gòu); 每一個數(shù)組結(jié)構(gòu)的出現(xiàn)必定會出現(xiàn)數(shù)組長度,它屬于字節(jié)數(shù)據(jù),用來表述接下來出現(xiàn)的數(shù)組結(jié)構(gòu)的長度; 再看class結(jié)構(gòu)class原結(jié)構(gòu)如下圖: 用兩種結(jié)構(gòu)來展示表達(dá)class結(jié)構(gòu)如下圖: 用這種方式來表達(dá)class文件結(jié)構(gòu)感覺更加清晰,class中包含的信息如下魔數(shù)、小版本、大版本、常量池、訪問標(biāo)注、當(dāng)前類、父類、接口、字段、方法、屬性。這樣一看一個class文件僅僅表達(dá)這些信息,其中常量池、接口、字段、方法數(shù)組結(jié)構(gòu)。 再看常量池常量池也是一個常量池數(shù)組,主要由以下表結(jié)構(gòu)組成: 常量池表結(jié)構(gòu)也分為兩種結(jié)構(gòu),存儲字符串的基礎(chǔ)結(jié)構(gòu)、由多個指向基礎(chǔ)結(jié)構(gòu)常量池數(shù)組索引的組合結(jié)構(gòu),所有常量池表第一個字節(jié)tag是用來確定結(jié)構(gòu)類型,根據(jù)表類型來判斷接下來字節(jié)是存儲還是指向。 常量池相當(dāng)于class文件的資源庫,存儲了后面字段、接口、方法等需要的字符串,后面結(jié)構(gòu)使用只需要指向常量池索引。 字段、方法、屬性方法與字段結(jié)構(gòu)如下圖: 字段與方法的結(jié)構(gòu)完全相似,他們最主要的區(qū)別在于attributes,方法的屬性包含Code、LineNumberTable、LocalVariableTable等屬性結(jié)構(gòu),用來表達(dá)方法的執(zhí)行過程、對應(yīng)源碼行號、本地變量等比字段需要更多的屬性來表達(dá)。 attribute種類巨多,并且還會持續(xù)的擴(kuò)展,就不能僅僅像常量池那樣通過固定字節(jié)來區(qū)分到底是那種attribute,而是通過attribute_name_index指向常量池中存儲的具體名稱,再通過attribute_length來確定attribute所占的位數(shù)。attribute是class文件中最靈活多變的結(jié)構(gòu),同時它的使用也存在class、方法、字段等結(jié)構(gòu)中。 總結(jié)字節(jié)數(shù)據(jù)就像是基礎(chǔ)數(shù)據(jù),而表結(jié)構(gòu)則是組合結(jié)構(gòu),而class文件通過這兩種結(jié)構(gòu)實現(xiàn)層層遞進(jìn),完整的存儲了需要表達(dá)的內(nèi)容,使得JVM拿到class文件能夠通過確定的結(jié)構(gòu)進(jìn)行層層解釋,這樣既精簡了class文件內(nèi)容也使JVM能快速、準(zhǔn)確的加載class文件。 通過學(xué)習(xí)class字節(jié)碼,能夠?qū)W習(xí)到一些平時很難了解到的知識,比如一個類支持的最大字段、方法數(shù)量,一個方法最長有多長等。不過學(xué)習(xí)到最重要的是JVM對數(shù)據(jù)的處理方式,class是如何通過最少的內(nèi)容表達(dá)出完整的信息的方式! Java程序員日常學(xué)習(xí)筆記,如理解有誤歡迎各位交流討論! |
|
來自: IT樂知 > 《程序員的私房筆記》