字段表集合介绍
字段表(Field_info)用于描述类或接口中声明的变量,包括类变量与成员变量,局部变量不在此表中。字段表集合由字段计数器与字段信息数据区两个部分组成,字段计数器用来统计Field_info的数量,字段数据区则由若干个Field_info组成,每一个Field_info代表了一个类变量或成员变量。
JVM会在类加载过程中的 “链接-准备” 阶段对字段表集合中的field_info逐个分配内存空间(在方法区中)并进行初始化,所以可以看出,准备阶段只会对static修饰的类变量进行内存空间分配与初始化。
图:字段表集合结构与field_info的结构
着重分析一下,每一个字段.class文件中是如何存储的,即每一个Field_info的结构
field_info struct {
u2 Access_flags /* 字段访问标记 */
u2 name_index
u2 descriptor_index
u2 attributes_count
attribute_info attributes
}
1、Access_flag - 字段访问标志
在介绍类访问标志的时候就提到过,每一个字段也有自己的访问标志位来标识这个字段的地方,就是Field_info中的字段访问标志,具体标志位的含义和值如下图:
比如 public final static int a = 10
将public、final、static在上图中对应的位置置为1后,得到这个变量的access_flags为:0x0019
2、name_index与descriptor_index
(1) name_index:长度2字节(16位),指向常量池中的一个CONSTANT_Utf8_info常量项,用于表示字段名称;
(2) descriptor_index:长度2字节(16位),指向常量池中的一个CONSTANT_Utf8_info常量项,用于表示该字段的数据类型;比如指向了“#10 = Utf8 I”,则表示是一个int类型的字段。
字段数据类型与常量池中简写对照表:
数据类型 | 常量池内对应简写字符 |
---|---|
Byte | B |
Char | C |
Double | D |
Float | F |
Int | I |
Long | J |
Short | S |
Boolean | Z |
Void | V |
数组类型 | [ 比如:int [] -> [I |
对象 | L 比如:String a=new String() -> Ljava/lang/String |
3、attributes_count与attributes
Field_info中的属性表;
首先需要明确两个点:
(1) 字段中可以有自己的属性表;
(2) 并不是所有的字段都需要用到属性表;
attribute_info struct {
u2 attribute_name_index; //可用于字段表中的属性名称,见下表
u4 attribute_length;
u1 info // attribute_length个info
}
(1) attribute_name_index:指向一个常量池中CONSTANT_Utf8_info的常量项,存放着这个属性的名称,比如常量池中的ConstantValue,就是用在这个地方的,除了ConstantValue之外,常见的属性如下表:
属性名称 | 含义 |
---|---|
ConstantValue | 该字段为final定义常量值 |
Signature | 支持泛型签名 |
Synthetic | 标识字段是否为编译器自动生成 |
RuntimeVisibleAnnotations | 标注运行时注解可见 |
RuntimeInvisibleAnnotations | 标注运行时注解不可见 |
不同的attribute_name_index所需要的info数量不同,每个info的意义也不同,即attribute_length不同,比如ConstantValue和Synthetic,两个属性attribute_length不同,每一个info也不同,这个会在分析具体属性的时候介绍。
4、.class文件中的字段表与分析
可以用javap反编译.class文件,查看一下字段表
java代码如下&#