“真正了不起的程序員對自己的程序的每一個字節(jié)都了如指掌”
--《程序員的自我修養(yǎng)》
引子:
寫了這么久的Java, 也看了一些關(guān)于JVM的書籍, 但是總感覺對JVM理解的還不是很夠, 不能很清楚的理解書中對常量池, 本地變量表, 操作數(shù)棧, 堆等的一些解釋, 因為只看文字總是不形象的, 對于程序員來說還是代碼來的直觀, 所以這次就來造一個大輪子, 自己動手寫一個Mini JVM, 而且是用Java來寫一個JVM. 這個JVM真的非常Mini, 里面不會實現(xiàn)垃圾回收, 也不會實現(xiàn)jdk中的類庫(因為是用Java來實現(xiàn), 所以直接調(diào)用Java的類庫就可以了, 其實道理是一樣的, 如果是用C++來實現(xiàn)JVM肯定調(diào)用的是C++的類庫). 這里用Java來實現(xiàn)Java虛擬機有一種自包含或者說遞歸的感覺, 因為用Java實現(xiàn)的虛擬機是可以跨平臺的, 但是運行這個Mini JVM又需要一個Java環(huán)境, 也就是Java虛擬機, 這個虛擬機是真正的oracle實現(xiàn)的虛擬機, 所以實際上這個Mini JVM只是在真正的虛擬機上虛擬了一個JVM.
1. Class File的文件結(jié)構(gòu)
1.1 總覽
因為實現(xiàn)的是Mini JVM, 所以直接從解析class文件作為起點, 而不是從將java源文件編譯成class文件開始(這個就相當(dāng)于實現(xiàn)一個java編譯器, 這個輪子造的就大發(fā)了。。。).
首先直觀的看一下一個具體的class文件的內(nèi)容長什么樣子

這個class文件對應(yīng)的java源文件

mini jvm就是要執(zhí)行這個java程序. (之后的mini jvm會支持條件判斷, 循環(huán)等功能)
1.2 class文件的組成

這里要注意一下, 因為class文件實際上就是一個緊湊的字節(jié)碼文件, 所以如果當(dāng)一個數(shù)據(jù)大于一個字節(jié)的時候, 是使用無符號大端模式進行存儲的, 大小端模式的區(qū)別請看這里.
2. 解析ClassFile
注: 接下來的解析會以我們要執(zhí)行的EmployeeV1的class文件為例進行講解.
2.1 魔數(shù)
每個class文件的前四個字節(jié)稱為魔數(shù), 它的作用是確定這個文件是否是一個能被虛擬機接受的Class文件. 虛擬機會對class文件進行校驗, 但是不僅僅是校驗一個class文件魔數(shù), 還會校驗比如其方法的字節(jié)碼指令是否是支持的等等. 而如果一個文件是class文件, 那么它的魔數(shù)就是CAFEBABE, 圖1-1可以看到確實如此.
2.2 Class文件的版本號
接下的四個字節(jié)是class文件的版本號, 也就是編譯出這個class文件的編譯器的版本號, 順序是前兩個字節(jié)是次版本號, 后兩個字節(jié)是版本號.
這里簡單介紹一個java的版本號. java的版本號是從45開始的, jdk1.0jdk1.1的版本號比較特殊是45.045.3, 之后每一個大版本發(fā)布版本號就加1(也就是jdk1.2的版本號是46), 所以在jdk1.1jdk1.2之間的小版本號可以有65535個(也就是jdk1.1的可以支持的版本范圍是45.045.65535), 至于為什么是65535應(yīng)該很容易就可以知道, 因為存儲小版本號的空間是2個字節(jié), 所以2個字節(jié)的無符號范圍就是0~65535.同時jdk保持了向下兼容性, 也就是高版本的jdk可以兼容也就是執(zhí)行低版本的class文件.
從圖1-1可以看到, 我使用的版本號是0x000034, 轉(zhuǎn)成十進制也就是次版本號是0, 主版本號是52,
所以計算一下就是jdk1.8(jdk1.2是46, 所以+6就是jdk8的版本號是52). 沒錯, 我就是用jdk1.8編譯這個java源文件的.
具體的class文件版本號的對應(yīng)關(guān)系可以看這里
3. 總結(jié)
這篇文章是解析class文件的開端, 也是整個class文件中最簡單的部分, 后面就會開始解析class文件中幾個最重要的部分的其中一個————常量池. 常量池對整個class文件的結(jié)構(gòu)組成至關(guān)重要, 要是沒有這個常量池, 我們編譯出來的class文件的大小將會大很多很多.
4. 代碼地址
5. 本系列其他文章
手把手教你擼一個Mini JVM系列(2)之解析Class File -- 常量池
手把手教你擼一個Mini JVM系列(3)之解析Class File -- 字段、方法、屬性
手把手教你擼一個Mini JVM系列(4)之執(zhí)行引擎
手把手教你擼一個Mini JVM系列(5)之源碼分析 -- 常量池、訪問標(biāo)志、類索引
手把手教你擼一個Mini JVM系列(6)之控制流 -- 條件判斷和循環(huán)