2.7 interfaces
interfaces数组记录所有当前类或接口直接实现的接口。interfaces数组中的每项值都是一个指向constant pool的索引值,这些值必须是CONSTANT_Class_info类型。数组中接口的顺序和源代码中接口定义的顺序相同。
2.8 fields
fields数组记录了类或接口中的所有字段,包括实例字段和静态字段,但不包含父类或父接口中定义的字段。fields数组中每项都是field_info类型值,它描述了字段的详细信息,如名称、描述符、字段中的attribute等。
| field_info |
||
| type |
descriptor |
remark |
| u2 |
access_flags |
记录字段的访问权限。见2.8.1 |
| u2 |
name_index |
constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段的名称。 |
| u2 |
descriptor_index |
constant_pool中的索引,CONSTANT_Utf8_info类型,指定字段的描述符(见附录C)。 |
| u2 |
attributes_count |
attributes包含的项目数。 |
| attribute_info |
attributes[attributes_count] |
字段中包含的Attribute集合。见2.8.2-2.8.7 |
注:fields中的项目和CONSTANT_Fieldref_info中的项目部分信息是相同的,他们主要的区别是CONSTANT_Fieldref_info中的项目不仅包含了类或接口中定义的字段,还包括在字节码中使用到的字段信息。不过这里很奇怪,为什么field_info结构中不把name_index和descriptor_index合并成fieldref_index,这样的class文件不是更加紧凑吗??不知道这是sun因为某些原因故意这样设计还是这是他们的失误??
2.8.1 字段访问权限
| 字段的访问权限 |
||
| Flag Name |
Value |
Remarks |
| ACC_PUBLIC |
0x0001 |
pubilc,包外可访问。 |
| ACC_PRIVATE |
0x0002 |
private,只可在类内访问。 |
| ACC_PROTECTED |
0x0004 |
protected,类内和子类中可访问。 |
| ACC_STATIC |
0x0008 |
static,静态。 |
| ACC_FINAL |
0x0010 |
final,常量。 |
| ACC_VOILATIE |
0x0040 |
volatile,直接读写内存,不可被缓存。不可和ACC_FINAL一起使用。 |
| ACC_TRANSIENT |
0x0080 |
transient,在序列化中被忽略的字段。 |
| ACC_SYNTHETIC |
0x1000 |
synthetic,由编译器产生,不存在于源代码中。 |
| ACC_ENUM |
0x4000 |
enum,枚举类型字段 |
注:接口中的字段必须同时设置:ACC_PUBLIC、ACC_STATIC、ACC_FINAL
2.8.2 ConstantValue Attribute (JVM识别)
| ConstantValue Attribute |
||
| type |
descriptor |
remark |
| u2 |
attribute_name_index |
constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute的名称(“ConstantValue”)。 |
| u4 |
attribute_length |
该Attribute内容的字节长度(固定值:2) |
| u2 |
constant_value_index |
constant_pool中的索引, CONSTANT_Integer_info(int,boolean,char、short、byte)、 CONSTANT_Float_info(float)、 Constant_Double_info(double)、 CONSTANT_Long_info(long) CONSTANT_String_info(String)类型 |
每个常量字段(final,静态常量或实例常量)都包含有且仅有一个ConstantValue Attribute。ConstantValue Attribute结构用于存储一个字段的常量值。
对一个静态常量字段,该常量值会在类或接口被初始化之前,由JVM负责赋给他们,即它在任何静态字段之前被赋值。
对一个非静态常量字段,该值会被虚拟机忽略,它的赋值由生成的实例初始化函数(
classA {
publicstaticfinalintfa= 10;
publicfinalintfa2= 30;
privatestaticintsa= 20;
static{
sa= 30;
}
}
生成的字节码如下:
// Compiled from Test.java (version 1.6 : 50.0, super bit)
class org.levin.insidejvm.miscs.staticinit.A {
public static final int fa = 10;
public final int fa2 = 30;
private static int sa;
static {};
0 bipush 20
2 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]
5 bipush 30
7 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]
10 return
public A();
0 aload_0 [this]
1 invokespecial java.lang.Object() [21]
4 aload_0 [this]
5 bipush 30
7 putfield org.levin.insidejvm.miscs.staticinit.A.fa2 : int [23]
10 return
作者“上善若水”