Java Class文件分析(一)——魔術(shù)、版本號(hào)、常量池

Java在誕生時(shí)就以一次編寫,到處運(yùn)行特點(diǎn)在各個(gè)平臺(tái)都可以進(jìn)行運(yùn)行。其實(shí)就是通過(guò)不同的編譯器(Javac編譯器,jrubyc編譯器,groovyc編譯器等等)將代碼編譯成規(guī)范的class文件,虛擬機(jī)只要接收到claas文件而并不關(guān)心是class文件時(shí)哪一種編譯器編譯的,這樣就到達(dá)了(write one,run anywhere)。所以要想更好的了解虛擬機(jī),下面我們走進(jìn)class文件中??!

Class文件是一組以8bit為基礎(chǔ)單位的二進(jìn)制流,各個(gè)數(shù)據(jù)項(xiàng)目嚴(yán)格按順序緊湊地排列在class文件中,中間無(wú)任何添割符。Class文件格式采用一種類似于C語(yǔ)言結(jié)構(gòu)體的偽結(jié)構(gòu)來(lái)儲(chǔ)存數(shù)據(jù),這種偽結(jié)構(gòu)只有兩種數(shù)據(jù):無(wú)符號(hào)數(shù)和表。

無(wú)符號(hào)數(shù)屬于基本的數(shù)據(jù)類型,以u(píng)1,u2,u3,u4,u8表示1個(gè)字節(jié),2個(gè)字節(jié),3個(gè)字節(jié),4個(gè)字節(jié),8個(gè)字節(jié),無(wú)符號(hào)數(shù)可以用來(lái)描述數(shù)字,索引引用,數(shù)量值或者按照UTF-8編碼構(gòu)成字符串。

表是由多個(gè)無(wú)符號(hào)數(shù)或者其它表作為數(shù)據(jù)項(xiàng)構(gòu)成的復(fù)合數(shù)據(jù)類型,所有表都習(xí)慣地以"_info"結(jié)尾。表用于描述由層次關(guān)系的復(fù)合結(jié)構(gòu)的數(shù)據(jù),整個(gè)class文件本質(zhì)上就是一張表。

class文件格式

類型 名稱 數(shù)量
u4 magic(魔數(shù)) 1
u2 minor_version(JDK次版本號(hào)) 1
u2 major_version(JDK主版本號(hào)) 1
u2 constant_pool_count(常量池?cái)?shù)量) 1
cp_info constan_pool(常量表) constant_pool_count-1
u2 access_flags(訪問(wèn)標(biāo)志) 1
u2 this_class(類引用) 1
u2 super_class(父類引用) 1
u2 interfaces_count(接口數(shù)量) 1
u2 interfaces(接口數(shù)組) interfaces_count
u2 fields_count(字段數(shù)量) 1
field_info fields(屬性表) fields_count
u2 methods_count(方法數(shù)量) 1
method_info methods(方法表) methods_count
u2 attributes_count(屬性數(shù)量) 1
attribute_info attributes(屬性表) attributes_count

由于方便,先講概念,最后翻譯一個(gè)class文件的形式進(jìn)行講解

一:魔數(shù):每個(gè)class文件的頭4個(gè)字節(jié)稱為魔數(shù),它的唯一作用就是確定這個(gè)文件是否為一個(gè)能被虛擬機(jī)接收的class文件。值為CAFEBABE,緊接著就是4個(gè)字節(jié)的版本號(hào),其中前兩個(gè)為次版本號(hào),后兩個(gè)為主版本號(hào)。到目前前8個(gè)字節(jié)就確定了。

二:版本號(hào):一個(gè)4個(gè)字節(jié),前兩字節(jié)表示次版本號(hào),后兩字節(jié)表示主版本號(hào)。

三:常量池:緊接著主次版本號(hào)就是常量池了,第一個(gè)是常量池?cái)?shù)量(占兩個(gè)字節(jié)),接下來(lái)就是常量池表,我以表的方式展現(xiàn)。

常量池表結(jié)構(gòu)

類型 名稱 數(shù)量
u1 tag(常量池的項(xiàng)目類型號(hào)) 1
u2 name_index(索引) 1

那么tag對(duì)應(yīng)的就是常量池的項(xiàng)目類型,下面我們來(lái)看看有哪些


image.png

讀取常量池的時(shí)候首先讀取標(biāo)志位,判斷常量類型,就可以知道對(duì)應(yīng)的結(jié)構(gòu),獲取對(duì)應(yīng)的信息了。
下面我們來(lái)一個(gè)簡(jiǎn)單的代碼,并編譯成class文件,以二進(jìn)制形式打開(kāi),人為來(lái)解析一下。
Java代碼

public class Test{
    
}

class文件


image.png

使用javap指令反編譯

C:\Users\GH\Desktop>javap -verbose Test.class
Classfile /C:/Users/GH/Desktop/Test.class
  Last modified 2018-8-8; size 182 bytes
  MD5 checksum f22f52551c287057ed6d62d392d5647e
  Compiled from "Test.java"
public class Test
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #3.#10         // java/lang/Object."<init>":()V
   #2 = Class              #11            // Test
   #3 = Class              #12            // java/lang/Object
   #4 = Utf8               <init>
   #5 = Utf8               ()V
   #6 = Utf8               Code
   #7 = Utf8               LineNumberTable
   #8 = Utf8               SourceFile
   #9 = Utf8               Test.java
  #10 = NameAndType        #4:#5          // "<init>":()V
  #11 = Utf8               Test
  #12 = Utf8               java/lang/Object
{
  public Test();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0
}
SourceFile: "Test.java"

參考:
https://blog.csdn.net/weixin_40234548/article/details/81507125

https://blog.csdn.net/mz4138/article/details/81984325

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容