欄位表集合 這個class文件的解析,分析得有點太久了.前面介紹類魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引和介面索引集合.下麵就應該到欄位表集合了. 欄位表集合 這個class文件的解析,分析得有點太久了.前面介紹類魔數,次版本號,主板本號,常量池入口,常量池,訪問標 ...
欄位表集合
這個class文件的解析,分析得有點太久了.前面介紹類魔數,次版本號,主板本號,常量池入口,常量池,訪問標誌,類索引,父類索引和介面索引集合.下麵就應該到欄位表集合了.
緊接著介面索引集合的就是欄位表的集合了.
欄位表(field_info)用於描述介面或者類中聲明的變數.欄位包括類級變數以及實例級變數,但是不包括在方法內部聲明的局部變數.
欄位表的結構:
類型 | 名稱 | 數量 |
u2 | access_flags | 1 |
u2 | name_index | 1 |
u2 | descriptor_index | 1 |
u2 | attributes_count | 1 |
attribute_info | attributes | attributes_count |
欄位修飾符放在access_flags項目中,它與類中的access_flags項目是非常相似的,都是一個u2的數據類型.
欄位訪問標誌:
標誌名稱 | 標誌值 | 含義 |
ACC_PUBLIC | 0x00 01 | 欄位是否為public |
ACC_PRIVATE | 0x00 02 | 欄位是否為private |
ACC_PROTECTED | 0x00 04 | 欄位是否為protected |
ACC_STATIC | 0x00 08 | 欄位是否為static |
ACC_FINAL | 0x00 10 | 欄位是否為final |
ACC_VOLATILE | 0x00 40 | 欄位是否為volatile |
ACC_TRANSTENT | 0x00 80 | 欄位是否為transient |
ACC_SYNCHETIC | 0x10 00 | 欄位是否為由編譯器自動產生 |
ACC_ENUM | 0x40 00 | 欄位是否為enum |
跟隨access_flags標誌的是兩項索引值:name_index和descriptor_index,它們都是對常量池的引用,分別代表著欄位的簡單名稱以及欄位方法和方法的描述符.
描述符的作用是用來描述欄位的數據類型,方法的參數列表(包括數量,類型以及順序)和返回值.根據描述符規則,基本數據類型以及代表無返回值的void類型都用一個大寫字元來表示,而對象類型則用字元加L加對象名的全限定名來表示.
描述符標誌含義:
標誌符 | 含義 |
B | 基本數據類型byte |
C | 基本數據類型char |
D | 基本數據類型double |
F | 基本數據類型float |
I | 基本數據類型int |
J | 基本數據類型long |
S | 基本數據類型short |
Z | 基本數據類型boolean |
V | 基本數據類型void |
L | 對象類型 |
對於數組類型,每一維度將使用一個前置的"["字元來描述.如一個定義為"java.lang.Stirng[ ]"類型的二維數組,將被記錄為:"[[Ljava/lang/Stirng",一個整型數組"int[]"將被記錄為"[I".
用描述符來描述方法時,按照先參數列表,後返回值的順序來描述,參數列表按照參數的嚴格順序放在一組小括弧"()"之內.
欄位表集合中不會列出從父類或者父介面中繼承而來的欄位,但有可能列出原來Java代碼中不存在的欄位,譬如在內部類中為了保持對外部類的訪問性,會自動添加指向外部類實例的欄位.另外,在Java語言中欄位是無法重載的,兩個欄位的數據類型,修飾符不管是否相同,都必須使用不一樣的名稱,但是對於位元組碼來講,如果連個欄位的描述符不一致,那欄位重名就是合法的.
下麵繼續前面分析的class文件:
源文件:
javap分析出來的常量池:
分析:
從上圖中分析可以看到0x00 01表示欄位表數據的個數,只有一個.0x00 02表示欄位表的private修飾符,從上面的欄位訪問標誌表可以看到.0x00 05表示欄位對應著第5個常量池,從javap分析出來的常量池,可以看到第5個常量池對應著m,再看源代碼我們定義的欄位確實就是m.0x00 06表示描述符標識,對應著第6個常量池,為I,那麼在對應我們的訪問標識符含義表,I 對應著int數據類型,再看源代碼m的數據類型確實就是int.