眾所周知史侣,我們?cè)谶\(yùn)行java代碼時(shí),首先java文件會(huì)被編譯成class文件担钮,然后將class文件裝載到j(luò)ava虛擬機(jī)中暇榴。那么這個(gè)class文件到底是什么呢厚棵,今天我們就來分析一下。
首先編寫一個(gè)測(cè)試類Test蔼紧,內(nèi)容很簡(jiǎn)單婆硬,就是輸出“hello,world”
使用WinHex工具打開這個(gè)Test.class文件奸例,會(huì)發(fā)現(xiàn)class文件內(nèi)容是這樣的:
觀察這些數(shù)據(jù)彬犯,不難發(fā)現(xiàn),class文件是一組以8位字節(jié)為基本單位的二進(jìn)制流查吊,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格地按順序排列在一起谐区,中間沒有空隙。
那么圖中這些16進(jìn)制數(shù)據(jù)代表什么含義呢逻卖?
1.每個(gè)class文件開頭的4個(gè)字節(jié)稱為“魔數(shù)”宋列,即圖中的“CA FE BA BE”,(一個(gè)16進(jìn)制數(shù)代表4位,兩個(gè)就是8位评也,剛好是一個(gè)字節(jié))炼杖,這個(gè)魔數(shù)的作用就是:確定這個(gè)文件是否是一個(gè)能被JVM接受的class文件戈鲁。
2.緊接著魔數(shù)的4個(gè)字節(jié)是Class文件的版本號(hào),其中5嘹叫、6兩個(gè)字節(jié)是次版本號(hào)(0x0000),7和8兩個(gè)字節(jié)是主版本號(hào)(0x0035)诈乒,也即10進(jìn)制中的53罩扇,代表這個(gè)文件是能被jdk1.8或以上版本虛擬機(jī)執(zhí)行的class文件。
3.再往后怕磨,就是常量池的入口喂饥,常量池可以理解成class文件中的資源倉庫。在java中有三種常量池:String常量池肠鲫、運(yùn)行時(shí)常量池和class常量池员帮。而我們這里講的就是class常量池,class常量池主要存放字面量和符號(hào)引用导饲,由于不同class文件常量池中的常量數(shù)是不同的捞高,所以會(huì)有兩個(gè)字節(jié)表示常量池計(jì)數(shù)器,記錄了常量的個(gè)數(shù)渣锦。這里是001E,是十進(jìn)制中的30硝岗,表示有29項(xiàng)常量(第0項(xiàng)常量是空出來的)。緊接著后面的0A,是常量池第一項(xiàng)常量的標(biāo)志位袋毙,屬于CONSTANT_Methodref_info類型型檀,代表類中方法的符號(hào)引用。其后的16進(jìn)制數(shù)以此類推听盖。
4.在常量池結(jié)束以后的兩個(gè)字節(jié)代表訪問標(biāo)志胀溺,用于識(shí)別一些類或接口層次的訪問信息。比如皆看,這個(gè)class是類還是接口仓坞,是否定義成public等。
5.訪問標(biāo)志后面是類索引悬蔽、父類索引和接口索引集合扯躺,class文件由這三項(xiàng)數(shù)據(jù)來確定這個(gè)類的繼承關(guān)系。類索引確定這個(gè)類的全限定名蝎困,父類索引確定這個(gè)類的父類的全限定名录语,由于Object是所有java類的父類,所以除了Object之外禾乘,任何類的父類索引都不為0.接口索引集合描述這個(gè)類實(shí)現(xiàn)了哪些接口澎埠。
6.而在后面的是字段表集合、方法表集合和屬性表集合始藕,此處就不再做說明蒲稳,如果有對(duì)這些感興趣的氮趋,可以去查閱資料書,推薦周志明的《深入理解java虛擬機(jī)》(非打廣告)
PS:java虛擬機(jī)這方面相關(guān)知識(shí)會(huì)在面試時(shí)問到江耀,而且理解了java虛擬機(jī)的原理剩胁,會(huì)對(duì)我們寫出更高效的代碼有很大幫助。