一、概述
在接口索引集合后面 的就是字段表集合了。字段表(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语言中字段是无法重载的,两个字段的数据类型,修饰符不管是否相同,都必须使用不一样的名称,但是对于字节码来讲,如果连个字段的描述符不一致,那字段重名就是合法的。
参考资料: