上篇介紹了字節碼文件的結構和其常量池分析。緊接其後呢,我們要去了解字段表的概念和組成結構。接着上篇裏的字節碼的常量池往後分析。
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等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代!