JVM虚拟机-Class文件之字段表集合
原创
©著作权归作者所有:来自51CTO博客作者沧海笑笑笑的原创作品,请联系作者获取转载授权,否则将追究法律责任
一、概述
在接口索引集合后面 的就是字段表集合了。字段表(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语言中字段是无法重载的,两个字段的数据类型,修饰符不管是否相同,都必须使用不一样的名称,但是对于字节码来讲,如果连个字段的描述符不一致,那字段重名就是合法的。