JavaClass文件結(jié)構(gòu)

1.Class文件概述

Class文件是一組以8位字節(jié)為基礎(chǔ)的二進(jìn)制流声离,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格按照順序緊湊地排列在Class文件之中吠裆,中間沒(méi)有添加任何分隔符养篓,這使得整個(gè)Class文件中存儲(chǔ)的內(nèi)容幾乎全部是程序的必要數(shù)據(jù)涂炎,沒(méi)有空隙存在忠聚。當(dāng)遇到需要占用8位字節(jié)的以上的空間的數(shù)據(jù)項(xiàng)時(shí)设哗,則會(huì)按照高位在前的方式分隔成若干個(gè)8位字節(jié)進(jìn)行存儲(chǔ)。

根據(jù)Java虛擬機(jī)規(guī)范的規(guī)定两蟀,Class文件格式采用一種類似于C語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu)來(lái)存儲(chǔ)數(shù)據(jù)网梢,這種偽結(jié)構(gòu)中只有兩種數(shù)據(jù)類型:
無(wú)符號(hào)和表,后面的解析都要以這兩種數(shù)據(jù)類型為基礎(chǔ)赂毯,所以這里要先介紹這兩個(gè)概念战虏。

1.1 無(wú)符號(hào)數(shù)和表

無(wú)符號(hào)數(shù)屬于基本的數(shù)據(jù)類型,以u(píng)1党涕、u2烦感、u4、u8來(lái)分別代表1個(gè)字節(jié)膛堤、2個(gè)字節(jié)手趣、4個(gè)字節(jié)和8個(gè)字節(jié)的無(wú)符號(hào)數(shù),
無(wú)符號(hào)數(shù)可以用來(lái)描述數(shù)字肥荔、索引引用绿渣、數(shù)量值或者按照UTF-8編碼構(gòu)成字符串值。

表是由多個(gè)無(wú)符號(hào)數(shù)或者其他表作為數(shù)據(jù)項(xiàng)構(gòu)成的復(fù)合數(shù)據(jù)類型燕耿,所有表都習(xí)慣性的以"_info"結(jié)尾中符。表用于描述
有層次關(guān)系的復(fù)合結(jié)構(gòu)的數(shù)據(jù),整個(gè)Class文件本質(zhì)上就是一張表誉帅。它由表6-1所示的數(shù)據(jù)項(xiàng)構(gòu)成淀散。

Class文件格式

1.2 魔數(shù)與Class文件的版本

每個(gè)Class文件的頭4個(gè)字節(jié)稱為魔數(shù)(Magic Number),它的唯一作用是確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)接受的Class文件蚜锨。

Class文件的魔數(shù)很有“浪漫氣息”吧凉,值為0xCAFEBABY(咖啡寶貝).

緊接著魔數(shù)的4個(gè)字節(jié)值是Class文件的版本號(hào):第5和第6個(gè)字節(jié)是次版本號(hào)(Minor Version),第7和第8個(gè)字節(jié)是主版本號(hào)
(Major Version)。Java的版本號(hào)是從45開始的踏志。

為了方便講解阀捅,現(xiàn)準(zhǔn)備了一段最簡(jiǎn)單的Java代碼(見(jiàn)代碼清單1-1)

代碼清單1-1

package org.fenixsoft.clazz;

public class TestClass {
    
    private int m;
        
    public int inc() {
        return m+1;
    }
}

下面是部分class文件中的內(nèi)容:

Class file

1.3 常量池

緊接著主次版本號(hào)之后的是常量池入口,常量池可以理解為Class文件之中的資源倉(cāng)庫(kù)针余,它是Class文件結(jié)構(gòu)中與其他項(xiàng)目關(guān)聯(lián)
最多的數(shù)據(jù)類型饲鄙,也是占用Class文件空間最大的數(shù)據(jù)項(xiàng)目之一,同時(shí)它還是在Class文件中第一個(gè)出現(xiàn)的表類型數(shù)據(jù)項(xiàng)目圆雁。

由于常量池常量的數(shù)量是不固定的忍级,所以在常量池的入口需要放置一項(xiàng)u2類型的數(shù)據(jù),代表常量池容量計(jì)數(shù)值(constant_pool_count)伪朽。

如下圖所示

常量池

常量池容量(偏移地址:0x00000008)為十六進(jìn)制數(shù)0x0016轴咱,即二進(jìn)制的22.這就代表常量池中有21項(xiàng)常量,索引值范圍為1-21.
在Class文件格式規(guī)范制定之時(shí),設(shè)計(jì)者將第0項(xiàng)常量空出來(lái)在于滿足后面某些指向常量池的索引值的數(shù)據(jù)在特定情況下需要表達(dá)
“不引用任何一個(gè)常量池項(xiàng)目”的含義朴肺。

常量池主要存放兩大類常量:字面量(Literal)和符號(hào)引用(Symbolic References)窖剑。字面量比較接近
Java語(yǔ)言層面的常量概念,如文本字符串,聲明為final的常量值等戈稿。而符號(hào)引用則屬于編譯原理方面的概念西土,
包括了下面三類常量:
 1.類和接口的全限定名(Full Qualified Name)
 2.字段的名稱和描述符(Descriptor)
 3.方法的名稱和描述符

常量池的每一項(xiàng)常量都是一個(gè)表,在JDK1.7之前共有11種結(jié)構(gòu)各不相同的表結(jié)構(gòu)數(shù)據(jù)鞍盗,在JDK1.7中為了更好支持動(dòng)態(tài)語(yǔ)言調(diào)用需了,
又額外增加了3種(CONSTANT_MethodHandle_info、CONSTANT_MethodType_info般甲、CONSTANT_InvokeDynamic_info)肋乍。

這14種表都有一個(gè)共同特點(diǎn),就是表開始的第一位是一個(gè)u1類型的標(biāo)志位(tag敷存,取值見(jiàn)下表中標(biāo)志列)墓造,代表當(dāng)前常量屬于哪種
常量類型.

常量池項(xiàng)目類型

1.3.1 javap的使用

在JDK的bin目錄中,有一個(gè)專門用于分析Class文件字節(jié)碼的工具:javap历帚,下圖列出了使用javap工具的-verbose參數(shù)輸出的
TestClass.class文件字節(jié)碼內(nèi)容滔岳。

javap輸出的字節(jié)碼內(nèi)容

1.3.2 常量池中的14種常量項(xiàng)的結(jié)構(gòu)總表

1.4 訪問(wèn)標(biāo)志

在常量池結(jié)束之后杠娱,緊接著的兩個(gè)字節(jié)代表訪問(wèn)標(biāo)志(access_flags)挽牢,這個(gè)標(biāo)志用于識(shí)別一些類或者接口層次的訪問(wèn)信息,
包括:這個(gè)Class是類還是接口摊求;是否定義為public類型禽拔;是否定義為abstract類型;如果是類的話室叉,是否被聲明為final等睹栖。

具體的標(biāo)志位以及標(biāo)志的含義見(jiàn)下圖

access_flags

access_flags中一共有16個(gè)標(biāo)志位可以使用,上圖只定義了其中8個(gè)茧痕,未使用的標(biāo)志位要求一律為0.

1.5 類索引野来、父類索引和接口索引集合

類索引(this_class)和父類索引(super_class)都是一個(gè)u2類型的數(shù)據(jù),而接口索引集合(interfaces)是一組u2類型的數(shù)據(jù)的集合
踪旷,Class文件中由這三項(xiàng)數(shù)據(jù)來(lái)確定這個(gè)類的繼承關(guān)系曼氛。

1.6 字段表集合

字段表(field_info)用于描述接口或者類中聲明的變量。字段(field)包括類級(jí)變量和實(shí)例級(jí)變量令野,但不包括在方法內(nèi)部聲明的
局部變量舀患。

字段表結(jié)構(gòu):

field_info

字段修飾符放在access_flags項(xiàng)目中,它與類中的access_flags項(xiàng)目非常類似的气破,都是一個(gè)u2的數(shù)據(jù)類型聊浅,其中可以設(shè)置的標(biāo)志
位的含義見(jiàn)下表:

class_field_access_flags

跟隨access_flags標(biāo)志的兩項(xiàng)索引值:name_index和descriptor_index。它們都是對(duì)常量池的引用,分別代表著字段的簡(jiǎn)單名稱
以及字段和方法的描述符低匙。

名詞解釋

全限定名:將類名中的'.'替換成'/'旷痕,例如:java.lang.Object的全限定名為java/lang/Object

簡(jiǎn)單名稱:指沒(méi)有類型和參數(shù)修飾的方法和字段名稱,例如Object的equals()方法的簡(jiǎn)單名稱為equals

描述符:用來(lái)描述字段的數(shù)據(jù)類型努咐,方法的參數(shù)列表(包括數(shù)量苦蒿、類型以及順序)和返回值。根據(jù)描述符規(guī)則
基本數(shù)據(jù)類型以及代表無(wú)返回值的void類型都用一個(gè)大寫字符來(lái)表示渗稍,而對(duì)象類型則用字符L加對(duì)象的全限
定名來(lái)表示佩迟。描述數(shù)組類型時(shí),每一維度將使用一個(gè)前置的'['字符來(lái)描述竿屹。

描述符標(biāo)識(shí)字符含義

用描述符來(lái)描述方法時(shí)报强,按照先參數(shù)列表,后返回值的順序描述拱燃,參數(shù)列表按照參數(shù)的嚴(yán)格順序放在一組小括號(hào)`()`
之內(nèi)秉溉。如方法void inc()的描述符為`()V`,方法java.lang.String()的描述符為`()Ljava/lang/String;`,
方法int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target,int targetOffset,int targetCount, int frmoIndex)的描述符為`([CII[CIII)I`

1.7 方法表集合

方法表的結(jié)構(gòu)與字段表的結(jié)構(gòu)相同,依次包括了訪問(wèn)標(biāo)志(access_flags)碗誉、名稱索引(name_index)召嘶、描述符索引(descriptor_index)
、屬性表集合(arrtibutes)幾項(xiàng)哮缺。

方法訪問(wèn)標(biāo)志

注意事項(xiàng):

如果父類方法在子類中沒(méi)有被重寫(Override)弄跌,方法表集合中就不會(huì)出現(xiàn)來(lái)自父類的方法信息。但同樣的
尝苇,有可能會(huì)出現(xiàn)編譯器自動(dòng)添加的方法铛只,最典型的便是類構(gòu)造器`<clinit>`方法和實(shí)例構(gòu)造器`<init>`方法。

1.8 屬性表集合

在Class文件糠溜、字段表淳玩、方法表都可以攜帶自己的屬性表集合,以用于描述某些場(chǎng)景專有的信息非竿。

具體屬性表在此不作講解蜕着,請(qǐng)參考《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(最新第二版)》的第六章

文件提取碼是2f30

聲明

本文摘自《深入理解Java虛擬機(jī):JVM高級(jí)特性與最佳實(shí)踐(最新第二版)》一書,為了更好的理解java的字節(jié)碼文件红柱。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末承匣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子豹芯,更是在濱河造成了極大的恐慌悄雅,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铁蹈,死亡現(xiàn)場(chǎng)離奇詭異宽闲,居然都是意外死亡众眨,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門容诬,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)娩梨,“玉大人,你說(shuō)我怎么就攤上這事览徒”范ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵习蓬,是天一觀的道長(zhǎng)纽什。 經(jīng)常有香客問(wèn)我,道長(zhǎng)躲叼,這世上最難降的妖魔是什么芦缰? 我笑而不...
    開封第一講書人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮枫慷,結(jié)果婚禮上让蕾,老公的妹妹穿的比我還像新娘。我一直安慰自己或听,他們只是感情好探孝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著誉裆,像睡著了一般顿颅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上找御,一...
    開封第一講書人閱讀 51,462評(píng)論 1 302
  • 那天元镀,我揣著相機(jī)與錄音绍填,去河邊找鬼霎桅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛讨永,可吹牛的內(nèi)容都是我干的滔驶。 我是一名探鬼主播,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼卿闹,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼揭糕!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起锻霎,我...
    開封第一講書人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤著角,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后旋恼,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吏口,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了产徊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片昂勒。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖舟铜,靈堂內(nèi)的尸體忽然破棺而出戈盈,到底是詐尸還是另有隱情,我是刑警寧澤谆刨,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布塘娶,位于F島的核電站,受9級(jí)特大地震影響痊夭,放射性物質(zhì)發(fā)生泄漏血柳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一生兆、第九天 我趴在偏房一處隱蔽的房頂上張望难捌。 院中可真熱鬧,春花似錦鸦难、人聲如沸根吁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)击敌。三九已至,卻和暖如春拴事,著一層夾襖步出監(jiān)牢的瞬間沃斤,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工刃宵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留衡瓶,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓牲证,卻偏偏與公主長(zhǎng)得像哮针,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子坦袍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 字節(jié)碼查看工具:WinHex 前言 Java虛擬機(jī)實(shí)現(xiàn)語(yǔ)言無(wú)關(guān)性的基石就是Class文件Java虛擬機(jī)提供的語(yǔ)言無(wú)...
    zlcook閱讀 7,133評(píng)論 4 18
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理十厢,服務(wù)發(fā)現(xiàn),斷路器捂齐,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法蛮放,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法奠宜,繼承相關(guān)的語(yǔ)法包颁,異常的語(yǔ)法缝其,線程的語(yǔ)...
    子非魚_t_閱讀 31,631評(píng)論 18 399
  • 文:梅子 致青春里說(shuō):很多人 一旦錯(cuò)過(guò)了就是陌路 同桌的你里說(shuō):時(shí)光不會(huì)老 只要你仍在 匆匆那年里說(shuō):不悔夢(mèng)歸...
    梅子梅子閱讀 3,388評(píng)論 30 48
  • 六月初的小城,華燈初上徘六,夜幕籠垂内边,百無(wú)聊賴的晚風(fēng)吹拂著她散落的留海,輕輕搖曳待锈,給這平靜的夜增添...
    1c74692e93ff閱讀 234評(píng)論 0 2