JAVA虛擬機入門(1)---------類文件結(jié)構(gòu)(上)

大家好僧须,由于最近被動態(tài)加載的知識卡住巍耗,而動態(tài)加載涉及到j(luò)ava虛擬機中的加載機制亮元,因此我決定花一定的時間來學(xué)習(xí)java虛擬機,特別是類加載部分史隆,主要參照《深入理解java虛擬機》這本書進行學(xué)習(xí),這本書的pdf版請前往鏈接獲取曼验。

http://download.csdn.net/detail/hollow12384/9606072

今天是java虛擬機的第一門課程泌射,主要講解的內(nèi)容如下:

(1)java虛擬機的語言無關(guān)性

(2)Class文件結(jié)構(gòu)概述

(3)解剖Class文件每個字節(jié)的含義

一:java虛擬機的語言無關(guān)性

java面世時就提出一個口號:”一次編寫,到處運行“鬓照,這句話表明了java的目標(biāo)是跨平臺運行熔酷,這個目標(biāo)最終怎么實現(xiàn)呢?自然是通過操作系統(tǒng)的

應(yīng)用層實現(xiàn)豺裆,而實現(xiàn)的方式就是虛擬機了纯陨。只要不同平臺的虛擬機和所有平臺都使用統(tǒng)一的程序存儲格式—–字節(jié)碼格式,就能達到跨平臺的目的留储。

這里就涉及到一個概念翼抠,什么是字節(jié)碼格式?

字節(jié)碼(英語:Bytecode)通常指的是已經(jīng)經(jīng)過編譯获讳,但與特定機器碼無關(guān)阴颖,需要直譯器轉(zhuǎn)譯后才能成為機器碼的中間代碼。字節(jié)碼通常不像源碼一樣可以讓人閱讀丐膝,而是編碼后的數(shù)值常量量愧、引用、指令等構(gòu)成的序列帅矗。

字節(jié)碼主要為了實現(xiàn)特定軟件運行和軟件環(huán)境偎肃、與硬件環(huán)境無關(guān)。字節(jié)碼的實現(xiàn)方式是通過編譯器和虛擬機器浑此。編譯器將源碼編譯成字節(jié)碼累颂,特定平臺上的虛擬機器將字節(jié)碼轉(zhuǎn)譯為可以直接執(zhí)行的指令。字節(jié)碼的典型應(yīng)用為Java bytecode凛俱。

通俗的說紊馏,字節(jié)碼就是源碼經(jīng)過編譯器后出來的東西。

字節(jié)碼本質(zhì)上就是二進制碼蒲犬。

不過朱监,java的強大之處不止在于跨平臺,java不僅具有平臺無關(guān)性原叮,而且具有很強的語言無關(guān)性赫编。什么意思呢巡蘸?

不管是什么語言,只要對應(yīng)的編譯器能夠?qū)⒊绦虼a編譯成Class文件擂送,java虛擬機并不在乎到底Class文件是由什么得來的悦荒,只要它符合Class文件結(jié)構(gòu)的要求,就能在java虛擬機中運行团甲。

二:Class文件結(jié)構(gòu)概述

前面我們已經(jīng)介紹了逾冬,java虛擬機運行的是Class文件,那么Class文件到底是什么呢躺苦?Class文件的結(jié)構(gòu)又該符合什么要求呢身腻?下面講解的就是這個內(nèi)容。

首先明確一點匹厘,Class文件是一組以8個字節(jié)為基礎(chǔ)單位的二進制流嘀趟。Class文件流中沒有分割符,這使得Class文件儲存的數(shù)據(jù)幾乎都是有效的關(guān)鍵的數(shù)據(jù)愈诚。有人可能會問她按,如果儲存的數(shù)據(jù)需要占用8個字節(jié)以上的空間怎么辦呢?這個時候就按照高位在前的方式炕柔,分割成若干個8個字節(jié)進行儲存酌泰。

那具體應(yīng)該怎么儲存呢?Class文件格式采用了類似于C語言結(jié)構(gòu)體的偽結(jié)構(gòu)進行儲存匕累。這種結(jié)構(gòu)只有兩種數(shù)據(jù)類型:無符號數(shù)和表陵刹。后面關(guān)于Class文件的結(jié)構(gòu)解析都要建立在這兩種數(shù)據(jù)類型上,因此先講解這兩種數(shù)據(jù)類型欢嘿。

(一)無符號數(shù)

無符號數(shù)屬于基本的數(shù)據(jù)類型衰琐,以u1,u2,u4,u8分別代表1個字節(jié),2個字節(jié)炼蹦,4個字節(jié)和8個字節(jié)的無符號數(shù)羡宙,無符號數(shù)可以用來描述數(shù)字,索引引用掐隐,數(shù)量值狗热,或者按照utf-8編碼構(gòu)成字符串值。

(二)表

表是由多個無符號數(shù)或其他表作為數(shù)據(jù)項構(gòu)成的復(fù)合數(shù)據(jù)類型瑟枫。所有的表都習(xí)慣性的用_info結(jié)尾斗搞,因此可以用這個來區(qū)分表和無符號數(shù)。整個Class本質(zhì)上就是一張表慷妙,它由以下的數(shù)據(jù)項構(gòu)成:

無論是無符號數(shù)還是表,如果需要描述同一個類型并且數(shù)據(jù)量不多允悦,經(jīng)常會使用一個前置的容量計數(shù)器加上若干個數(shù)據(jù)項的形式膝擂,這個時候稱這一系列連續(xù)的某個類型的數(shù)據(jù)為某一類型的集合虑啤。

三:解剖Class文件每個字節(jié)的含義

第二點說明了Class文件采用無符號數(shù)和表來儲存數(shù)據(jù),但是具體怎么儲存呢架馋?儲存的規(guī)則是什么呢狞山?

在正式講解之前,建議大家先下載安裝一個軟件WinHex叉寂,我們將使用這個軟件來將.class字節(jié)碼文件轉(zhuǎn)化為16進制數(shù)進行解析萍启。

接下來先對Class文件解析的規(guī)則進行解釋:

整個.class文件轉(zhuǎn)化為16進制后就是按照上述這張表進行解析。

接下來就耐心地對表里的每一項進行詳細(xì)解釋屏鳍。

在解釋之前勘纯,由于我比較傾向于用實例解釋,因此我用一個實在的java項目生成的.class文件進行解析钓瞭。

當(dāng)然驳遵,這個java項目十分簡單,只有一個類山涡,

這個類位于這個包內(nèi):

到這個包所在的目錄堤结,打開bin,在里面就可以找到.class文件(注意鸭丛,我們是對.class文件解析而不是.java文件竞穷,還記得嗎?進入java虛擬機的是.class文件而不是.java文件)

然后用winHex打開這個.class文件鳞溉,就可以看到.class文件的16進制表示了瘾带。

好了,做足了準(zhǔn)備工作穿挨,就可以開始解析了月弛。

ps:由于篇幅較長,因此我將這部分分為兩篇博客科盛,這篇博客講解的前四個屬性帽衙,剩余的屬性見JAVA虛擬機入門(1)———-類文件結(jié)構(gòu)(下)

(一)魔數(shù)(4個字節(jié))

Class文件的前4個字節(jié)稱為魔數(shù),是用于確定這個文件是否是可以被java虛擬機接受的.class文件贞绵,為啥不用后綴名來判斷呢厉萝?當(dāng)然是因為

后綴名實在是太容易改了,而文件格式制定者只要采用標(biāo)示文件格式的魔數(shù)榨崩,并且魔數(shù)沒有被其他人采用谴垫,那就可以起到標(biāo)示的作用了。Class文件的魔數(shù)是

CAFE BABE(咖啡寶貝)母蛛,是否特別好記翩剪?看我們解析出來的16機制文件前四個字節(jié),正是CAFE BABE彩郊!

(二)版本號(4個字節(jié))

魔數(shù)后面緊跟著的就是版本號了前弯,包括次版本號和主版本號蚪缀,各占2個字節(jié)。在我們的例子中就是0000和0034恕出,0000說明此版本號為0询枚,0034說明主版本號為52,因此編譯器jdk的版本就是52.0浙巫。

(三)常量池(不定個字節(jié))

常量池是Class文件中出現(xiàn)的第一個表類型數(shù)據(jù)類型金蜀,而且占據(jù)著Class文件的最大空間,同時與其他項目的關(guān)聯(lián)最多的畴。因此渊抄,常量池是一個比較復(fù)雜并且重要的內(nèi)容。

大家也可能注意到苗傅,在介紹常量池的時候抒线,我用了“不定個字節(jié)”,說明常量池的字節(jié)長度是不確定的渣慕。那怎么確定常量池到底是到哪里呢嘶炭?這取決于常量池

的前兩個字節(jié)u2,在這個例子中也就是0016逊桦,這表示一共有21個常量眨猎,為什么不是22呢(0016的十進制表示就是22)?因為第一個字節(jié)是空出來

的强经,用于后面指向常量池的索引數(shù)據(jù)在特定情況下表達“不引用任何一個常量池項目”的意思睡陪,這種情況下將索引值置為0(也就是常量池第一個字節(jié))就行了。

常量池中的常量主要包括兩大類:Leteral和符號引用(Symbolic Reference)匿情。Literal類似于java描述的常量兰迫,如文本字符串,final修飾的類型炬称。符號引用主要包括三類常量:

(1)類和接口的全限定名

(2)字段的名稱和限定符

(3)方法的名稱和限定符

關(guān)于類加載的知識在下節(jié)解析汁果。

這里拋出一個問題:為什么要使用符號引用?

推薦閱讀

回到對16進制.class文件的解析玲躯,常量池中的每一個常量都是一個表据德,一共有11種表結(jié)構(gòu),他們具有共同的特征跷车,就是第一個字節(jié)(u1)表示的是這種表的類型棘利,接下來的字節(jié)根據(jù)他們各自的類型進行解析。主要參考下面的表朽缴。

還是舉我們的例子善玫,第9個字節(jié)和第10個字節(jié)(0016)表示常量池一共有21個常量,第一個常量的標(biāo)志位是07密强,根據(jù)上面的表得知為

CONSTANT_Class_Info(記得之前說過嗎蝌焚,以info結(jié)尾的一般就是表結(jié)構(gòu)了)裹唆,并且u2指定的是全限定名常量項的索引誓斥,在這個例子中

u2是0002只洒,說明全限定名常量項在第二個常量中。第二個常量的tag是01劳坑,說明是CONSTANT_Utf8_info毕谴,u2是0011,說明

utf8字符串占據(jù)的字節(jié)數(shù)是17個字節(jié)距芬,也就是從6A一直到下一行的74涝开,這17個字節(jié)代表的就是全限定名常量的名字。這里就涉及到怎么翻譯utf8縮

略編碼了框仔。

從“\u0001”到”\u007f”之間的字符用一個字節(jié)表示舀武,”\u0080”到”\u07ff”用兩個字節(jié)表示,從”\u0800”到”\uffff”用三個字節(jié)表示离斩。

在WinHex中银舱,當(dāng)你選中這17個字節(jié)時,旁邊會自動顯示相應(yīng)的圖形跛梗,在這個例子中顯示的是”javaLearning/test“寻馏,正是這個項目的完整名字!再接下去的解析也是一樣的核偿,就不多說了诚欠。

不過這里要重點說明一下,由于Class的方法漾岳,字段等都需要引用到01轰绵,也即是CONSTANT_Utf8_info,因此

CONSTANT_Utf8_info的數(shù)量直接決定了java中方法和字段的數(shù)量尼荆,CONSTANT_Utf8_info指明長度的是length字

段左腔,長度為u2,也就是16個bit耀找,共有65535種可能排序翔悠,因此方法數(shù)的瓶頸就是65535了!如果方法數(shù)超過了這個數(shù)野芒,那么將導(dǎo)致無法編譯蓄愁。

(四)訪問標(biāo)志(2個字節(jié))

常量池21個常量過后就是訪問標(biāo)志了,在這個例子中是在Offset為000000D0這一行的76 61過后的兩個字節(jié)狞悲,也就是00 21撮抓。首先先來看訪問標(biāo)志都有什么,以及每個對應(yīng)的16進制數(shù)是什么摇锋?

注意表中的每個屬性不一定與其他屬性相斥丹拯,比如ACC_PUBLIC和ACC_FINAL站超,一個類既可以聲明為public,也可以同時聲明為final乖酬,這個時候的標(biāo)志值就是兩者的或運算了(0001 | 0010)死相。

回歸到我們的例子中,我們的例子只有聲明了public咬像,那是不是就是0001呢算撮?請注意,ACC_SUPER說明了县昂,jdk1.2以后編譯出來的

類都會有這個標(biāo)志肮柜,而根據(jù)前面我們讀到的jdk版本號,肯定大于1.2倒彰,因此絕對是帶有這個標(biāo)志的审洞。所以真正的標(biāo)志位為0001 | 0020 =

0021,和我們讀出來的結(jié)果相符合了待讳。

好了芒澜,這就是類文件結(jié)構(gòu)最基本的前面幾個字節(jié)碼了,感興趣的各位可以看JAVA虛擬機入門(1)——-類文件結(jié)構(gòu)(下)???

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末耙箍,一起剝皮案震驚了整個濱河市撰糠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌辩昆,老刑警劉巖阅酪,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汁针,居然都是意外死亡术辐,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進店門施无,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辉词,“玉大人,你說我怎么就攤上這事猾骡∪鹛桑” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵兴想,是天一觀的道長幢哨。 經(jīng)常有香客問我,道長嫂便,這世上最難降的妖魔是什么捞镰? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上岸售,老公的妹妹穿的比我還像新娘践樱。我一直安慰自己,他們只是感情好凸丸,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布拷邢。 她就那樣靜靜地躺著,像睡著了一般甲雅。 火紅的嫁衣襯著肌膚如雪解孙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天抛人,我揣著相機與錄音,去河邊找鬼脐瑰。 笑死妖枚,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的苍在。 我是一名探鬼主播绝页,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼寂恬!你這毒婦竟也來了续誉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤初肉,失蹤者是張志新(化名)和其女友劉穎酷鸦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牙咏,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡臼隔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了妄壶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片摔握。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖丁寄,靈堂內(nèi)的尸體忽然破棺而出氨淌,到底是詐尸還是另有隱情,我是刑警寧澤伊磺,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布盛正,位于F島的核電站,受9級特大地震影響奢浑,放射性物質(zhì)發(fā)生泄漏蛮艰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望壤蚜。 院中可真熱鬧即寡,春花似錦、人聲如沸袜刷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽著蟹。三九已至墩蔓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間萧豆,已是汗流浹背奸披。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留涮雷,地道東北人阵面。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像洪鸭,于是被迫代替她去往敵國和親样刷。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

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