Java字節碼結構剖析二:字段表 原

上篇介紹了字節碼文件的結構和其常量池分析。緊接其後呢,我們要去了解字段表的概念和組成結構。接着上篇裏的字節碼的常量池往後分析。

access_flags

訪問標誌信息包括該class文件是類還是接口,是否定義成public,是否是abstract,如果是類,是否被申明爲final。access_flags 的取值範圍和相應含義見下表。

 

 

 

 

我們的字節碼裏該位置的16進製表示是0×0021。0×0021=0×0001 ^ 0×0020。即代表該類的訪問修飾是public的。ACC_SUPER這裏不做介紹,看看JVM規範對他的描述,瞭解即可。

ACC_SUPER 標誌用於確定該 Class 文件裏面的 invokespecial 指令使用的是哪一種執行語義。目前 Java 虛擬機的編譯器都應當設置這個標誌。ACC_SUPER 標記是爲了向後兼容舊編譯器編譯的 Class 文件而存在的,在 JDK1.0.2 版本以前的編譯器產生的 Class 文件中,access_flag 裏面沒有 ACC_SUPER 標誌。同時,JDK1.0.2 前的 Java 虛擬機遇到 ACC_SUPER 標記會自動忽略它。

this_class_name

類索引,this_class 的值必須是對 constant_pool 表中項目的一個有效索引值。constant_pool 表在這個索引處的項必須爲 CONSTANT_Class_info 類型常量,表示這個 Class 文件所定義的類或接口。

在我的字節碼文件中,該16進制值爲0×0005=5。通過常量池信息,最終他指向的是一個utf-8字符串,com/shengsiyuan/jvm/bytecode/MyTest2。即類的全限定名。

#5 = Class              #38            // com/shengsiyuan/jvm/bytecode/MyTest2
#38 = Utf8              com/shengsiyuan/jvm/bytecode/MyTest2

super_class_name

父類索引,對於類來說,super_class 的值必須爲 0 或者是對 constant_pool 表中項目的一個有效索引值。

在字節碼文件中,父類索引爲0x000A=10。即父類是 java/lang/Object

#10 = Class              #43            // java/lang/Object
#43 = Utf8               java/lang/Object

interfaces_count

接口計數器,interfaces_count 的值表示當前類或接口的直接父接口數量。

我們的代碼沒有實現任何接口,所以該項值爲0,即0×0000。

interfaces[]

接口表,interfaces[]數組中的每個成員的值必須是一個對 constant_pool 表中項目的一個有效索引值,它的長度爲 interfaces_count。

我們代碼沒有接口,所以我們的字節碼文件裏沒有這項了。所以 interfaces_count 後面就直接是字段計數器和字段表。

fields_count

字段計數器,fields_count 的值表示當前 Class 文件 fields[]數組的成員個數。也就是當前類的類字段和實例字段的個數。

我們源代碼裏定義了3個字段,1個類字段,2個實例字段。所以fields_count爲3。查看對應字節碼文件的16進製表示0×0003=3。

fields[]

字段表用於描述類和接口中聲明的變量。這裏的字段包含了類級別變量以及實例變量,但是不包括方法內部聲明的局部變量。

field_info結構格式如下:

field_info {
    u2 access_flags;
    u2 name_index;
    u2 descriptor_index;
    u2 attributes_count;
    attribute_info attributes[attributes_count];
}

access_flags 項的值是用於定義字段被訪問權限和基礎屬性的掩碼標誌。access_flags 的取值範圍和相應含義見如下表:

 

 

 

 

看在我字節碼中的16進製表示,0×0000=0。0代表沒有修飾符的意思。看我們的源碼:String str = “Welcome”;,即默認修飾符。

  • name_index 項的值必須是對常量池的一個有效索引。常量池在該索引處的項必須是CONSTANT_Utf8_info結構,表示一個有效的字段的非全限定名。

在字節碼裏是0x000B=11。常量池11處:

#11 = Utf8               str

表示字段的名稱爲“str”。

  • descriptor_index 項的值必須是對常量池的一個有效索引。常量池在該索引處的項必須是CONSTANT_Utf8_info結構,表示一個有效的字段的描述符。

字節碼中,0x000C=12。看常量池:

#12 = Utf8               Ljava/lang/String;

表示該字段是String類型。

在JVM規範中,每個變量/字段都有描述信息,描述信息主要作用是描述字段的數據類型、方法的參數列表(包括數量,類型與順序)與返回值。根據描述符規則,基本數據類型和代表無返回值的void類型都用一個大寫字符來表示,對象類型則使用字符L加對象的全限定名稱來表示。爲了壓縮字節碼文件的體積,對於基本數據類型,JVM都只使用一個大寫字母表示,如下所示:B-byte、C-char、D-double、F-float、I-int、J-long、S-short、Z-boolean、V-void、L-對象類型,如Ljava/lang/String。

對於數組類型來說,每一個緯度使一個前置的[表示,如int[]被記錄爲[I,String[][]被記錄爲[[Ljava/lang/String;。

  • attributes_count的項的值表示當前字段的附加屬性的數量。

在字節碼裏,0x0000=0。即該字段沒有附加屬性。

  • attributes[]

attributes 表的每一個成員的值必須是 attribute結構,一個字段可以有任意個關聯屬性。

因爲該字段沒有附加屬性,所以這項數據沒有。

以上就是字段表裏的第1個字段的完整字節碼信息描述。也就是我們定義的『str』字段的信息。我們代碼裏還有2個字段 private int x = 5 和 public static Integer in = 10。我便不再描述了,大家可以緊接着我後面把這兩個字段的信息解析出來。

歡迎工作一到五年的Java工程師朋友們加入Java架構開發: 854393687
羣內提供免費的Java架構學習資料(裏面有高可用、高併發、高性能及分佈式、Jvm性能調優、Spring源碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章