class结构

翻译自Chapter 4.The class File Format

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}

magic

用来识别class文件,固定值:0xCAFEBABE。关于0xCAFEBABE还有一个故事java魔法之0xCAFEBABE

minor_version, major_version

minor_version和major_version项的值是此类文件的次要版本号和主要版本号。主要版本号和次要版本号一起确定类文件格式的版本。如果类文件具有主版本号M和次版本号m,则我们将其类文件格式的版本表示为M.m.因此,类文件格式版本可以按字典顺序排序,例如,1.5 <2.0 <2.1。

当且仅当v位于某个连续范围Mi.0≤v≤Mj.m时,Java虚拟机实现可以支持版本v的类文件格式。 Java SE平台的发行版级负责确定Java虚拟机实现符合的范围。

JDK 1.0.2版中的Oracle Java虚拟机实现支持包含45.0到45.3类的类文件格式。 JDK发布的1.1.*支持类文件格式版本范围为45.0到45.65535(含)。对于k≥2,JDK版本1.k支持45.0到44 + k.0范围内的类文件格式版本。

constant_pool_count

constant_pool_count项的值等于constant_pool表中的条目数加1。如果constant_pool索引大于零且小于constant_pool_count,则认为它是有效的,§4.4.5中注明了long和double类型的常量。

constant_pool[]

constant_pool是一个存储各种字符串常量、类和接口名称、字段名称以及在Class文件结构和子结构中引用的其他常量的结构表。每个constant_pool表的条目的格式由它的第一个‘tag’字节指出。
constant_pool表的索引从1到constant_pool_count-1。

access_flags

access_flags项的值是用来表示访问权限和类或者接口的属性的标志的掩码。设置时,每个标志的解释如表4.1所示。

Table 4.1. 类访问和属性修饰符

Flag Name Value Interpretation

ACC_PUBLIC 0x0001 Declared public; 可以被外部包访问。
ACC_FINAL 0x0010 Declared final; 不允许有子类。
ACC_SUPER 0x0020 在invokespecial指令调用时特别处理超类方法。
ACC_INTERFACE 0x0200 标识接口类。
ACC_ABSTRACT 0x0400 Declared abstract; 不能被实例化。
ACC_SYNTHETIC 0x1000 Declared synthetic; 不再源代码中体现。
ACC_ANNOTATION 0x2000 Declared as an annotation type.
ACC_ENUM 0x4000 Declared as an enum type.

可以用ACC_SYNTHETIC标志标记类,以指示它是由编译器生成的,并且不出现在源代码中。

ACC_ENUM 标志指示这个类或者它的父类是被定义为枚举类型。

一个接口的特征是被设置ACC_INTERFACE标志。如果没有设置ACC_INTERFACE标志,这个类文件定义的是一个类而不是一个接口。

如果这个类设置了ACC_INTERFACE标志,它的ACC_ABSTRACT也一定被设置了(JLS §9.1.1.1)。这样的类文件不能设置其ACC_FINAL,ACC_SUPER或ACC_ENUM标志。

注解类型必须设置ACC_ANNOTATION标志。如果设置了ACC_ANNOTATION标志,则也必须设置ACC_INTERFACE标志。如果这个类文件没有设置ACC_INTERFACE标志,它可以设置Table 4.1中除ACC_ANNOTATION之外的任何其他标志。但是,这个类不能同时设置ACC_FINAL和ACC_ABSTRACT标志(JLS §8.1.1.2)。

ACC_SUPER标志指示如果它出现在此类中,则由invokespecial指令(§invokespecial)表示两个备用语义中的哪一个。 Java虚拟机指令集的编译器应设置ACC_SUPER标志。

ACC_SUPER标志的存在是为了与旧编译器为Java编程语言编译的代码向后兼容。在版本1.0.2之前的Oracle JDK中,编译器生成了ClassFile access_flags,其中现在表示ACC_SUPER的标志没有指定含义,并且Oracle的Java虚拟机实现忽略了该标志(如果已设置)。

表4.1中未分配的access_flags项的所有位都保留供将来使用。它们应该在生成的类文件中设置为零,并且应该被Java虚拟机的实现忽略。

this_class

this_class项的值必须是一个在constant_pool表中的有效索引。constant_pool索引index处的条目必须是一个在此类文件中定义的类或者接口的CONSTANT_Class_info结构。

super_class

对于一个类,父类项的值要么是0,要么是一个在常量池表中的有效索引。如果父类项的值非0,则在常量池表索引index位置上的条目一定是CONSTANT_Class_info结构(§4.4.1),指示class文件中定义的类的直接父类。直接父类或者任何其他父类都不会在它的Class文件结构的access_flags项上设置ACC_FINAL标志。

如果父类项的值是0,则这个类文件必须是Object类,唯一个没有直接父类的类或者接口。

对于一个接口,父类项的值必须总是一个在常量池表中的有效索引。在此索引上的常量池条目必须是一个CONSTANT_Class_info结构指示Object类。

interfaces_count

interfaces_count项的值是这个类或者接口类型的直接父接口的数量。

interfaces[]

接口数组中的每个值都必须是一个在常量池表中的有效索引。在常量池表中索引是interfaces[i](0<=i<interfaces_count)的值上的每个条目必须是表示一个接口的CONSTANT_Class_info 结构 (§4.4.1),这个接口是这个类或者这个接口类型的父接口,在类型的来源中给出的从左到右的顺序。

fields_count

fields_count项的值是字段表中field_info结构的数量。field_info结构指示所有字段,包括在这个类或者接口类型中的类变量和实例变量。

fields[]

字段表中的每个值都必须是一个给出在这个类或者接口中的字段的完整描述的field_info(§4.5)结构。字段表仅仅包含在这个类或者接口中定义的那些字段。不包含从父类或者父接口中继承的字段。

methods_count

methods_count的值给出了方法表中的methods_info结构的数量。

methods[]

方法表中的每个值都必须是一个给出一个在这个类或者接口中方法的完整描述的method_info结构。如果一个method_info结构的access_flags项未设置ACC_NATIVE和ACC_ABSTRACT标志,Java虚拟机也提供了实现这个方法的指令。

method_info结构指示了所有在这个类或者接口类型中定义的方法,包括实例方法,类方法,实力初始化方法以及任何类或者接口初始化方法(§2.9)。方法表不包含继承自父类或者父接口的方法。

attributes_count

attributes_count项的值给出了在这个类的属性表中的属性数量。

attributes[]

属性表的每个值都必须是一个attribute_info(§4.7)结构。

本规范定义的属性出现在ClassFile结构的属性表中的是InnerClasses(§4.7.6),EnclosingMethod(§4.7.7),Synthetic(§4.7.8),Signature(§4.7.9), SourceFile(§4.7.10),SourceDebugExtension(§4.7.11),不推荐使用(§4.7.15),RuntimeVisibleAnnotations(§4.7.16),RuntimeInvisibleAnnotations(§4.7.17)和BootstrapMethods(§4.7.21)属性。

如果一个Java虚拟机的实现实现识别出class文件的版本在49.0版本以上,它必须识别和正确的读取在49.0或者更高版本class文件的文件结构的属性表中找到的签名(§4.7.9),RuntimeVisibleAnnotations (§4.7.16)和 RuntimeInvisibleAnnotations (§4.7.17) 属性。

如果Java虚拟机实现识别出51.0或更高版本的class文件,它必须识别和正确的读取在51.0或更高版本的class文件的文件结构的属性表中找到的BootstrapMethods (§4.7.21) 属性。

一个Java虚拟机的实现需要静默忽略它无法识别的ClassFile结构的属性表中的任何或所有属性。不允许在本规范中定义的属性影响类文件的语义,但仅允许提供其他描述性信息(第4.7.1节)。