深入JVM之 class文件解析

我們知道.java文件要轉化成程序運行要經過一系列過程的,大體:javac(前端編譯器)將.java文件編譯成class文件 --> JIT(後端編譯器/即時編譯器)將.class文件實時將.class解釋翻譯成機器碼,供計算機識別。
JIT的解釋過程有個叫熱點代碼的東西,類似緩存,它會將使用次數較多的代碼提前編譯好,提高效率。
下面進入重點,這個隨着java語言一起誕生,又隨着JVM一同壯大的class文件究竟是怎麼工作的?它的內部又包含哪些元素?
class文件,示例:

cafe babe 0000 0034 0021 0a00 0400 1907
001a 0a00 1b00 1c07 001d 0100 063c 696e
6974 3e01 0003 2829 5601 0004 436f 6465
0100 0f4c 696e 654e 756d 6265 7254 6162
6c65 0100 124c 6f63 616c 5661 7269 6162……
  1. magic number
    class文件打開,如上,入眼是一堆整齊的十六進制數字,在文件開頭的四個字節,也就是 cafebabe是java文件的magic number,用於標識這是一個合法的class文件。
  2. 版本號
    緊接着magic number的兩個字節代表次版本號,可以看到這裏的示例是0000,因爲從JAVA8開始,版本號只採用主版本,次版本號暫時停用。
    次版本號之後的兩個字節代表主版本號。高版本的JDK可以向下兼容以前版本的Class文件,但是無法運行以後版本的Class文件。
  3. 常量池。
    沒錯,就是那個運行時常量池年少時的模樣,它存儲了這個java類主要的數據,class文件中其他部分的內容大多都是指向這裏的引用。它是一個表結構。
    在主版本號的兩個字節之後,是常量池的入口,這個入口是一個兩個字節的無符號數,constatn_pool_count用來代表整個常量池的大小。(因爲常量池的大小是不定量,隨類信息多少變化)。
    常量池主要存儲兩大類數據:字面量和字符引用。字面量主要是文本字符串、final常量,字符引用則是一個‘字符串表示的堆某個類/方法的引用’,會在類加載的解析階段被置換爲直接引用。
    常量池裏面還有很多信息,如常量池中數據類型在JDK1.7時有是一種,有表示int、double、long的,也有表示字符串的,也有CONSTANT_Class_info類型來表示類的全限定名等的類型。
    常量池類型表
  4. 訪問標識
    常量池之後的兩個字節,用於標識該類的訪問限定。比如:這是類還是接口,這是不是抽象類,是public還是private、是不是JVM自動生成的類、這是不是註解/枚舉類等等。
    訪問標識表
  5. 類索引、父類索引、接口索引
    訪問標識之後的兩位,是一個常量池的索引下標,到常量池取出來的值是類本身的全限定類名。
    再之後的兩位,同樣是全限定類名,只不過是父類的全限定類名。
    再之後的兩位,是接口的count,這個count表示該類實現了幾個接口。這兩位之後的動態集合則是具體的接口全限定類名所對應的常量池索引下標。
  6. 字段表
    接口索引之後,是字段表,字段表用於描述接口或者類中聲明的變量,包括類級變量和實例級變量(是否是static),但不包括在方法內部聲明的局部變量。
  7. 方法表
    方法表同字段表,用於描述方法的集合。
  8. 屬性表
    在Class文件、字段表和方法表都可以攜帶自己的屬性信息,這個信息用屬性表進行描述,用於描述某些場景專有的信息。
    屬性表示意表
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章