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

原文鏈接:http://blog.csdn.net/hollow12384/article/details/52189590
轉(zhuǎn)載請(qǐng)注明出處

大家好华弓,這篇博客是繼JAVA虛擬機(jī)入門(1)—–類文件結(jié)構(gòu)(上)的冯勉,沒看過那篇博客的最好先看那篇博客~(鏈接:http://blog.csdn.net/hollow12384/article/details/52183804
由于始終圍繞上篇博客的例子進(jìn)行講解戈盈,這次還是先把圖放出來初澎,這圖和上篇博客的一模一樣制恍,只是為了大家方便觀看墨林。

這里寫圖片描述

(五)類索引饥伊、父類索引,接口類索引集合(至少4個(gè)字節(jié))
承接在訪問標(biāo)志后的就是類索引荷鼠、父類索引句携,接口類索引集合。類索引用于確定這個(gè)類的全限定名允乐,有2個(gè)字節(jié)矮嫉;父類索引用于確定這個(gè)類的父類的全限定名,有2個(gè)字節(jié)牍疏,且除了Object類外蠢笋,其余類這個(gè)索引不可能為空(都默認(rèn)繼承Object);接口類索引集合跟之前的常量池接口差不多鳞陨,前兩個(gè)字節(jié)表示一共有多少個(gè)接口昨寞,如果是00 00說明沒有implement 接口。
還是針對(duì)上篇博客中的例子厦滤,跟在0021后面的就是 00 01援岩,說明這個(gè)類的全限定名要去第一個(gè)常量找,找到常量池中的第一個(gè)常量掏导,為07 00 02享怀,上次我們解析過了,07代表的是CONSTANT_Class_info碘菜,是一個(gè)指向類的索引凹蜈,這里0002指向的是第二個(gè)常量限寞,由于之前已經(jīng)解析過了,這里就不再贅述仰坦,第二個(gè)常量解析出來的結(jié)果正是javaLearning/test履植,也就是這個(gè)類的全限定名。
緊跟著00 01的是00 03悄晃,說明父類權(quán)限定名要去第三個(gè)常量找玫霎,步驟和上面的一模一樣,解析出來的結(jié)果是Java/lang/Object妈橄,沒錯(cuò)吧庶近!沒有繼承其他類的類默認(rèn)繼承Object。接下來就是00 03后面的00 00眷蚓,我們說過鼻种,00 00代表的是沒有接口,在我們這個(gè)例子中確實(shí)沒有繼承接口沙热,bingo叉钥。

(六)字段表
回顧一下,到目前為止篙贸,我們已經(jīng)解析了魔數(shù)投队,版本號(hào),常量池爵川,訪問標(biāo)志和類索引敷鸦、父類索引和接口索引集合,接下來將正式進(jìn)入類里面探索每一個(gè)字段在字節(jié)碼文件中怎么表示的寝贡。在索引集合后跟著的就是字段表了扒披。什么是字段呢?舉個(gè)例子吧兔甘,private int k = 0谎碍,這里的k就可以理解為是字段鳞滨。當(dāng)然洞焙,字段實(shí)際上是包括它的屬性的,比如private和int等拯啦。首先我們先看一下字段表的結(jié)構(gòu)澡匪,這會(huì)指引我們對(duì)字節(jié)碼進(jìn)行解析:

這里寫圖片描述

要注意表中的數(shù)據(jù)是針對(duì)于一個(gè)field(字段)的,但是我們知道褒链,在一個(gè)類中唁情,往往有許多字段,比如private int a; private int b; 這樣的話就需要一個(gè)計(jì)數(shù)器來表示一共有多少個(gè)字段了甫匹,因此字段表一開始的2個(gè)字節(jié)就是用于表示一共有多少個(gè)字段的甸鸟。在我們的例子中是00 01惦费,也就是說只有一個(gè)字段,這是當(dāng)然抢韭。因?yàn)槲覀兙椭挥幸粋€(gè)字段:private int a = 1;
接下來薪贫,我們將結(jié)合實(shí)例對(duì)里面每一個(gè)字段進(jìn)行解釋。

(1)access_flags(2個(gè)字節(jié))
還記得(四)中的訪問標(biāo)志嗎刻恭,這里的access_flags和那個(gè)差不多瞧省。下面是access_flags可以設(shè)置的一些屬性。

這里寫圖片描述

不過注意里面的這些屬性鳍贾,有些是可以在一起設(shè)置的鞍匾,有些是相斥的,具體哪些相斥可以參考java制定規(guī)則骑科,這里由于將焦點(diǎn)放在解析字節(jié)碼文件橡淑,因此不多贅述。在我們的例子中咆爽,access_flags是在00 01后的00 02梳码,根據(jù)上面的屬性表可以得知對(duì)應(yīng)的是ACC_PRIVATE,正確伍掀。

(2)name_index(2個(gè)字節(jié))
name_index表示的是字段的簡單名稱的索引掰茶,何謂簡單名稱呢?這是相對(duì)于全限定名而言的蜜笤,在(五)中我們已經(jīng)知道濒蒋,全限定名就是類似于javaLearning/test?這種結(jié)構(gòu)的(包/類),而簡單名稱則就是一個(gè)名字而已把兔,比如private int a = 1(還是這個(gè)例子)沪伙,簡單名稱就是a。知道這個(gè)概念后县好,看回例子围橡,name_index為00 05,去常量池的第5個(gè)常量找缕贡,對(duì)應(yīng)的位置是Offset為00000030那一行的01 0001 61翁授,這個(gè)就是第五個(gè)常量了,01表示是CONSTANT_Utf8_Info晾咪,0001說明長度為1個(gè)字節(jié)收擦,61表示的是‘a(chǎn)’,怎樣谍倦?是不是我們例子中的那個(gè)字段a塞赂!再一次成功解出。

(3)descriptor_index(2個(gè)字節(jié))
我們已經(jīng)解析出來private和a昼蛀,但是還有一個(gè)關(guān)鍵的a的類型還沒解析出來宴猾,那應(yīng)該怎么得到a的類型int呢圆存?這就需要描述符了。描述符是一個(gè)相對(duì)于前面兩個(gè)復(fù)雜一點(diǎn)的東西仇哆。它主要是用于描述字段的數(shù)據(jù)類型辽剧、方法的參數(shù)列表(包括數(shù)量、類型和順序)和返回值税产。首先我們先講解描述符的描述規(guī)則怕轿,一旦理解這個(gè),解析也就so easy了辟拷。根據(jù)描述符的描述規(guī)則撞羽,基本數(shù)據(jù)類型(int,byte衫冻,char诀紊,double,float隅俘,long邻奠,short,boolean)以及代表無返回值的void都用一個(gè)大寫字符表示为居,而對(duì)象類型就用L + 對(duì)象全限定名表示碌宴,而數(shù)組類型每一個(gè)維度都用一個(gè)前置的”[“表示。舉個(gè)例子:String[][][]表示為[[[Ljava.lang.String蒙畴,int[]表示為[I具體如下表:

這里寫圖片描述

大家也注意到了贰镣,在說描述符時(shí),我并沒有局限于描述字段膳凝,而是提到了方法碑隆,沒錯(cuò),描述符也用于描述方法蹬音。用描述符描述方法時(shí)上煤,按照先參數(shù)列表再返回值的順序描述。參數(shù)列表按照參數(shù)的嚴(yán)格順序放置在()中著淆。繼續(xù)舉個(gè)例子:int getIntTest()用描述符描述就是()I劫狠,void k(int a,String[]k,int b)用描述符描述就是(I[Ljava.lang.StringI)V。相信大家對(duì)描述符怎么得來的應(yīng)該已經(jīng)有了一定理解牧抽,接下來就是實(shí)戰(zhàn)了嘉熊。再次獻(xiàn)上那個(gè)遠(yuǎn)古的例子(參照本博客剛開頭那張表)遥赚,在實(shí)例中descriptor_index對(duì)應(yīng)的字節(jié)碼是00 06扬舒,去常量池中第六個(gè)常量中找,位置是offset為00000030的01 00 01 49凫佛,對(duì)應(yīng)的值為I讲坎,也就回答了我們?cè)谇懊嫣岬降膯栴}了孕惜,這個(gè)I就是int。在descriptor_index后跟著的是attrubute_count晨炕,但是因?yàn)樵谶@里是00 00衫画,說明沒有其他屬性了。不過如果是final static int a = 9瓮栗;那么屬性表集合將會(huì)有一個(gè)指向常量池中9的屬性削罩。

(七)方法表集合
在字段表后面就是方法表集合了,由于方法表集合和字段表集合十分類似费奸,因此直接給出方法表結(jié)構(gòu)以及方法表訪問結(jié)構(gòu)方法表結(jié)構(gòu)如下:
[圖片上傳中弥激。。愿阐。(5)]
方法訪問標(biāo)志如下:

這里寫圖片描述

接著就直接對(duì)實(shí)例中的方法表進(jìn)行解析了(畢竟真的和字段表很像):
看到Offset為000000E0中的00 02微服,說明方法表一共有兩個(gè)方法。咦缨历?我們不是只寫了一個(gè)方法嗎以蕴?怎么這里說是兩個(gè)?其實(shí)辛孵,要注意到丛肮,每個(gè)類都會(huì)有屬于自己的構(gòu)造函數(shù),如果自己沒有寫構(gòu)造函數(shù)的話魄缚,那么編譯器會(huì)幫我們添加一個(gè)實(shí)例構(gòu)造器腾供,因此這多出來的一個(gè)方法就是構(gòu)造方法了。
接下來看第一個(gè)方法鲜滩,00 01說明是ACC_PUBLIC伴鳖,00 07找到常量池的第七個(gè)常量,位于Offset為00000030的01 00 06 3C 69 6E 69 74 3E徙硅,翻譯出來就是榜聂,再看00 08指向常量池的第8個(gè)常量,讀出來為()V嗓蘑,說明是返回值為0须肆,參數(shù)為空的函數(shù);接下來的00 01說明屬性表只有一個(gè)屬性桩皿,是00 09豌汇,讀取第9個(gè)常量,讀出來是Code泄隔,說明這個(gè)屬性是方法的字節(jié)碼描述拒贱。總結(jié)一下就是我們讀出來一個(gè)public的無參構(gòu)造函數(shù),而關(guān)于方法的字節(jié)碼描述在后面的屬性表中會(huì)進(jìn)行解釋逻澳。
第二個(gè)方法是00 01 —-> public闸天,00 09,找到第九個(gè)常量斜做,0A 00 03 00 0B苞氮,關(guān)于常量池中的tag在上篇博客有給出一張表,根據(jù)里面的規(guī)則進(jìn)行轉(zhuǎn)化瓤逼,最后的結(jié)果是getIntTest笼吟,就是方法的名字了。
注意:
(1)一個(gè)類如果沒有override一個(gè)父類的方法霸旗,那么父類的方法不會(huì)出 現(xiàn)在這個(gè)類的常量池中
(2)在java中重載一個(gè)方法赞厕,其實(shí)除了一個(gè)和原方法一模一樣的名稱外,還需要一個(gè)與原方法不同的特征簽名定硝。什么是特征簽名呢皿桑?特征簽名是一個(gè)方法中各個(gè)參數(shù)在常量池中的字段引用的集合,而返回值是不屬于方法中參數(shù)的蔬啡,因此無法通過返回值來對(duì)一個(gè)原有的方法進(jìn)行重載诲侮。
(3)在Class文件格式中,特征簽名的范圍更大一些箱蟆,只要不是完全一樣的描述符就可以了沟绪,因此只有返回值不同也是可以算作重載的。因此同一個(gè)類中如果兩個(gè)類只有返回值不同時(shí)可以的空猜,因?yàn)檫@個(gè)類被編譯成.class字節(jié)碼文件后的描述符是不一樣的

七:總結(jié)
原本在方法表后就是屬性表了绽慈,但是還記得我在類文件結(jié)構(gòu)(上)一開篇提到的嗎?我是為了學(xué)習(xí)熱修補(bǔ)而開始學(xué)習(xí)java虛擬機(jī)的辈毯,因此關(guān)于屬性表和后面的知識(shí)坝疼,解析起來方法上是一樣的,為了讓我的目標(biāo)更明確谆沃,我決定類文件結(jié)構(gòu)就到此為止钝凶。
當(dāng)然,如果有比較多的朋友還想我寫屬性表和后面的內(nèi)容唁影,我會(huì)找個(gè)時(shí)間寫一遍的耕陷。
下一篇博客就是類加載機(jī)制了,這一塊是直接和熱修補(bǔ)技術(shù)相關(guān)的据沈,因此希望大家繼續(xù)耐心地支持我哟沫,謝謝。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末锌介,一起剝皮案震驚了整個(gè)濱河市嗜诀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖裹虫,帶你破解...
    沈念sama閱讀 211,948評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肿嘲,死亡現(xiàn)場(chǎng)離奇詭異融击,居然都是意外死亡筑公,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,371評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門尊浪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來匣屡,“玉大人,你說我怎么就攤上這事拇涤〉纷鳎” “怎么了?”我有些...
    開封第一講書人閱讀 157,490評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵鹅士,是天一觀的道長券躁。 經(jīng)常有香客問我,道長掉盅,這世上最難降的妖魔是什么也拜? 我笑而不...
    開封第一講書人閱讀 56,521評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮趾痘,結(jié)果婚禮上慢哈,老公的妹妹穿的比我還像新娘。我一直安慰自己永票,他們只是感情好卵贱,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,627評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著侣集,像睡著了一般键俱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上世分,一...
    開封第一講書人閱讀 49,842評(píng)論 1 290
  • 那天方妖,我揣著相機(jī)與錄音,去河邊找鬼罚攀。 笑死党觅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斋泄。 我是一名探鬼主播杯瞻,決...
    沈念sama閱讀 38,997評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼炫掐!你這毒婦竟也來了魁莉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,741評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎旗唁,沒想到半個(gè)月后畦浓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,203評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡检疫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,534評(píng)論 2 327
  • 正文 我和宋清朗相戀三年讶请,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片屎媳。...
    茶點(diǎn)故事閱讀 38,673評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡夺溢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出烛谊,到底是詐尸還是另有隱情风响,我是刑警寧澤,帶...
    沈念sama閱讀 34,339評(píng)論 4 330
  • 正文 年R本政府宣布丹禀,位于F島的核電站状勤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏双泪。R本人自食惡果不足惜持搜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,955評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望攒读。 院中可真熱鬧朵诫,春花似錦、人聲如沸薄扁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,770評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽邓梅。三九已至脱盲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間日缨,已是汗流浹背钱反。 一陣腳步聲響...
    開封第一講書人閱讀 32,000評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留匣距,地道東北人面哥。 一個(gè)月前我還...
    沈念sama閱讀 46,394評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像毅待,于是被迫代替她去往敵國和親尚卫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,562評(píng)論 2 349

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

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 10,930評(píng)論 6 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法尸红,類相關(guān)的語法吱涉,內(nèi)部類的語法刹泄,繼承相關(guān)的語法,異常的語法怎爵,線程的語...
    子非魚_t_閱讀 31,598評(píng)論 18 399
  • 代理 代理設(shè)計(jì)模式的作用:1.A對(duì)象監(jiān)聽B對(duì)象的一些行為特石,A成為B的代理2.B對(duì)象想告訴A對(duì)象一些事情,A成為B的...
    挖掘機(jī)閱讀 237評(píng)論 0 0
  • 跟他硬著說話吧,真心是沒有什么價(jià)值撒轮,但是你順著他說話吧乞旦,氣立馬就消贼穆,你身邊有這樣的他嘛题山?是不是瞬間感覺事半功倍的節(jié)...
    星在遠(yuǎn)程閱讀 228評(píng)論 0 0
  • 放手磨練顶瞳,愛的至高境界 ——茹心 這些日子,因?yàn)榭傇趶S房與山卡拉的宿舍兩邊奔走愕秫,加之交通不便慨菱,公司便安排泉叔專車接...
    茹心閱讀 355評(píng)論 0 1