一、概述
在接口索引集合後面 的就是字段表集合了。字段表(field_info)用於描述接口或者類中聲明的變量。字段包括類級變量以及實例級變量,但是不包括在方法內部聲明的局部變量。
二、字段表集合的構成
1.字段計數器
字段表集合是由很多field_info組成的,所以字段表集合的前兩個字節表示有多少個字段,佔兩個字節,16位。
2.field_info
每個field_info的結構如下表所示:
類型 | 名稱 | 數量 |
u2 | access_flags | 1 |
u2 | name_index | 1 |
u2 | descriptor_index | 1 |
u2 | attributes_count | 1 |
attribute_info | attributes | attributes_count |
3.access_flags
access_flags爲字段修飾符,也稱字段訪問標誌。access_flag佔2個字節,16位,它與類中的access_flags項目是非常相似的,包括如下類型:
標誌名稱 | 標誌值 | 含義 |
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 |
某個字段擁有哪些標誌符,就是要用訪問標識取|操作:
如0x0001|0x0008爲0x0009。
4.name_index和descriptor_index
name_index和descriptor_index,是對常量池的引用,name_index指字段的簡單名稱,descriptor_index指字段描述符。
descriptor_index描述符用來描述字段的數據類型,基本數據類型用一個大寫字符來表示,而對象類型則用字符加L加對象名的全限定名來表示。
標誌符 | 含義 |
B | 基本數據類型byte |
C | 基本數據類型char |
D | 基本數據類型double |
F | 基本數據類型float |
I | 基本數據類型int |
J | 基本數據類型long |
S | 基本數據類型short |
Z | 基本數據類型boolean |
V | 基本數據類型void |
L | 對象類型 |
對數組類型,每一維將使用一個"["字符來描述.如一個Stirng[][]類型的二維數組,將被記錄爲:[[Ljava/lang/Stirng,一個整型數組"int []"將被記錄爲"[I"。
三、實例拆解
定義一個類:
public class HelloWord{
public int i;
private Long l;
protected String[][] arrs;
public Object test(){return null;}
}
javap -verbose HelloWord.class
public class com.csdn.reader.HelloWord
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#21 // java/lang/Object."<init>":()V
#2 = Class #22 // com/csdn/reader/HelloWord
#3 = Class #23 // java/lang/Object
#4 = Utf8 i
#5 = Utf8 I
#6 = Utf8 l
#7 = Utf8 Ljava/lang/Long;
#8 = Utf8 arrs
#9 = Utf8 [[Ljava/lang/String;
#10 = Utf8 <init>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Utf8 LineNumberTable
#14 = Utf8 LocalVariableTable
#15 = Utf8 this
#16 = Utf8 Lcom/csdn/reader/HelloWord;
#17 = Utf8 test
#18 = Utf8 ()Ljava/lang/Object;
#19 = Utf8 SourceFile
#20 = Utf8 HelloWord.java
#21 = NameAndType #10:#11 // "<init>":()V
#22 = Utf8 com/csdn/reader/HelloWord
#23 = Utf8 java/lang/Object
{
public int i;
descriptor: I
flags: ACC_PUBLIC
protected java.lang.String[][] arrs;
descriptor: [[Ljava/lang/String;
flags: ACC_PROTECTED
public com.csdn.reader.HelloWord();
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 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/csdn/reader/HelloWord;
public java.lang.Object test();
descriptor: ()Ljava/lang/Object;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aconst_null
1: areturn
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this Lcom/csdn/reader/HelloWord;
}
四、總結
字段表集合中不會列出從父類或者父接口中繼承而來的字段,但有可能列出原來Java代碼中不存在的字段和方法,譬如在內部類中爲了保持對外部類的訪問性,會自動添加指向外部類實例的字段。
另外,在Java語言中字段是無法重載的,兩個字段的數據類型,修飾符不管是否相同,都必須使用不一樣的名稱,但是對於字節碼來講,如果連個字段的描述符不一致,那字段重名就是合法的。
參考資料: