Java class文件格式

0 概述

这实际上是《The Java® Virtual Machine Specification - Java SE 8 Edition》中第四章内容(The class File Format)的部分翻译。主要目的是整理阅读笔记,让我自己看得明白,在这个前提下,尽量让别人看得明白,如果读者觉得我写得很混乱,还请自行阅读原文,不便之处敬请见谅。如有错误,还请指正(拉到页面底部点击『联系我』就可以发邮件给我)。


每一个class文件都包含了一个单独的class或者interface的定义。尽管一个class或者interface并不是有一个以文件形式存在的外部表达,但是下面还是通俗地将class或interface的任何有效表达称为类文件格式(the class file format)。

一个类文件由一个8位字节流组成。 所有的16位,32位和64位量分别通过读取2、4、8个连续的8位字节来构造。 多字节数据项总是以big-endian顺序存储,其中高字节排在第一位。 在Java SE平台中,此格式由接口java.io.DataInputjava.io.DataOutput以及类如java.io.DataInputStreamjava.io.DataOutputStream支持。

本章定义了自己的一组表示类文件数据的数据类型:

  • 类型u1u2u4分别表示一个无符号的一个,两个或四个字节数量(即1 byte、2 byte和4 byte)。

在Java SE平台中,这些类型可以通过接口java.io.DataInputreadUnsignedBytereadUnsignedShortreadInt等方法读取。

1 ClassFile结构

一个class文件包含一个单独的ClassFile结构:

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];
}

ClassFile结构中的各个item含义如下:

1.1 magic

魔法数字,用于标识class文件格式,固定为0xCAFEBABE

1.2 minor_version, major_version

minor_version和major_version组合到一起,决定了class文件格式的版本。

假设class文件的major_version为$M$,minor_version为$m$,那么我们将class文件格式的版本记为$M.m$,因此,这个版本号可以按字典序排序,例如$1.5<2.0<2.1$。

一个JVM的实现可以支持的class文件格式版本记为$v$,当且仅当$v$落在连续区间 $M_i.0 \leq v \leq M_j.m$ 时成立。

JVM实现所遵循的Java SE平台的release level决定了其支持范围。

例如

  • Oracle对JDK release 1.0.2的JVM实现支持的class文件格式版本为$[45.0, 45.3]$
  • JDK release 1.1.* 支持$[45.0, 45.65535]$
  • 对于$k \geq 2$,JDK release $1.k$ 支持范围为$[45.0, 44+k.0]$

1.3 constant_pool_count

constant_pool[]中的条目数量+1

1.4 constant_pool[]

constant_pool是一个结构表,表示ClassFile结构及其子结构中引用的各种

  • 字符串常量
  • 类和接口名
  • 字段名
  • 其他常量。

每个constant_pool表项的格式由第一个“标记(tag)”字节表示。
constant_pool表下标的取值范围是$[1,\ constant\_pool\_count)$

1.5 access_flags

access_flags 项的值是用于表示对此类或接口的访问权限和属性的标志的掩码。

16bit

Flag Name Value 二进制 十进制表示 Interpretation
ACC_PUBLIC 0x0001 00000000 00000001 1 声明public
ACC_FINAL 0x0010 00000000 00010000 16 声明final
ACC_SUPER 0x0020 00000000 00100000 32 当调用invokespecial指令时,特殊对待父类方法
ACC_INTERFACE 0x0200 00000010 00000000 512 指明这是interface而非class
ACC_ABSTRACT 0x0400 00000100 00000000 1024 声明abstract
ACC_SYNTHETIC 0x1000 00010000 00000000 4096 声明synthetic,在源码中不存在
ACC_ANNOTATION 0x2000 00100000 00000000 8192 指明这是注解
ACC_ENUM 0x4000 01000000 00000000 16384 指明这是enum

1.6 this_class

this_class的值必须是constant_pool[]的有效下标。constant_pool[this_class]必须为CONSTANT_Class_info结构,表示了在此class文件中定义的类或者接口。

1
2
3
4
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}

1.7 super_class

super_class的值也必须是constant_pool[]的有效下标。

对于类来说,

  • 如果此值不是0, 则constant_pool[super_class]必须为CONSTANT_Class_info结构,表示了此class文件定义的类的直接父类。
  • 如果此值为0,则此class文件必须表示Object类,这是唯一没有直接父类的类或者接口。

对于接口来说,没有规定。

1.8 interfaces_count

指明了此类的直接父接口的数量。

1.9 interfaces[]

里面的每个值都必须是constant_pool[]的有效下标。所指向的constant_pool中的条目必须为CONSTANT_Class_info结构,指明了其直接父接口。

1.10 fileds_count

给出fields[]field_info结构的数量。field_info结构表示了此类或接口所声明的所有field,包括class variables和instance virables(也就是静态变量和实例变量)。

1.11 fields[]

所有值都必须为field_info结构,给出对变量的完整描述。只包含由此类或者接口声明的变量,不包括继承而来的。

1
2
3
4
5
6
7
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

1.12 methods_count

给出methods[]method_info结构的数量

1.13 methods[]

所有值都必须为method_info结构。

如果ACC_NATIVEACC_ABSTRACT标志都没有在method_info里的access_flags中设置,实现此方法的JVM指令也要提供。

methods[]表达了此class or intreface声明的所有方法,包括实例方法、类方法、实例初始化方法和class or interface 初始化方法,不包括继承而来的方法。

1
2
3
4
5
6
7
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

1.14 attributes_count

size of attributes[]

1.15 attributes[]

1
2
3
4
5
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}

2 The Internal Form of Names

2.1 Binary Class and Interface Names

class文件结构中,class和interface的名字总是以一种全限定(fully qualified)的形式表达的,被称为binary names(JLS §13.1)。这些名字总是表达为CONSTANT_Utf8_info结构。

类和接口名称是从那些CONSTANT_NameAndType_info结构中引用的, 它们的名称是其描述符的一部分, 并且来自所有CONSTANT_Class_info结构

由于历史原因, 类文件结构中出现的binary names的语法不同于JLS §13.1中记录的二进制名称的语法。标识符(identifiers)构成了binary names,通常用ASCII码(.)分割各个标识符,在这种内部形式中,替换为了ASCII码(/)。标识符本身必须是未限定的名称(unqualified names)。

2.2 Unqualified Names 未限定的名称

方法、field、本地变量和形式参数的名称都存储为unqualified names

一个unqualified names必须包含至少一个Unicode码(Unicode code point),并且不能包含以下ASCII字符:., ;, [, /(即,句号、分号、左方括号和斜线)。

方法名的约束还要加上不能出现ASCII字符<>(即左尖括号和右尖括号),例外方法为

  • <init>
  • <clinit>

3 Descriptors 描述符

描述符是用于表示field或者方法的字符串。

3.1 Grammer Notaion 语法符号

(先定义用于描述描述符构成的语法):
描述符是使用语法指定的。语法是一组生产、 描述字符序列如何形成各种语法正确的描述符。

  • 语法的终端符号以固定宽度字体显示。
  • 非终结名称符号以斜体类型显示。
  • 非终结名称的定义由定义的非终结名称的名称引入,后跟冒号。
  • 非终结名称的一个或多个可选定义随后将跟随后续行。
  • 生产右侧的语法 {x} 表示 x 的零个或多个匹配项。
  • 生产右侧的短语 (one of) 表示以下行或行上的每个终端符号都是可选的定义。

3.2 Field Descriptors

field descriptors的说明:

FieldType term Type Interpretation
B byte signed byte
C char Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16
D double double-precision floating-point value
F float single-precision floating-point value
I int integer
J long long integer
L ClassName ; reference an instance of class ClassName
S short signed short
Z boolean true or false
[ reference one array dimension

例子:

  • 一个Object实例表示为:Ljava/lang/Object;
  • 一个多维数组double[][][]表示为[[[D

3.3 Method Descriptors 方法描述符

例子:

  • 1

    1
    Object m(int i, double d, Thread t) {...}

    描述符为:(IDLjava/lang/Thread;)Ljava/lang/Object;

4 The Constant Pool

Java 虚拟机指令不依赖于类、接口、类实例或数组的运行时布局。相反, 指令指的是 constant_pool 表中的符号信息。

constant_pool中的所有条目都具有以下的一般结构:

1
2
3
4
cp_info {
u1 tag;
u1 info[];
}

其中,tag用于指示cp_info条目的类型,info数组的内容随tag的值而变化。每个标记字节必须后跟两个或多个字节, 以提供有关特定常量的信息。tag的取值范围如下:

Constant Type Value
CONSTANT_Class 7
CONSTANT_Fieldref 9
CONSTANT_Methodref 10
CONSTANT_InterfaceMethodref 11
CONSTANT_String 8
CONSTANT_Integer 3
CONSTANT_Float 4
CONSTANT_Long 5
CONSTANT_Double 6
CONSTANT_NameAndType 12
CONSTANT_Utf8 1
CONSTANT_MethodHandle 15
CONSTANT_MethodType 16
CONSTANT_InvokeDynamic 18

4.1 CONSTANT_Class_info

1
2
3
4
CONSTANT_Class_info {
u1 tag;
u2 name_index;
}

tag的值为7,表示这是一个CONSTANT_Classname_index必须是constant_pool的有效下标,指向的必须是一个CONSTANT_Utf8_info结构。也就是说指向了常量池中表示类名的字符串常量。类名表达为internal form,例如:

  • int[][]表达为[[I
  • Thread[]表达为[Ljava/lang/Thread;

4.2 CONSTANT_Fieldref_info, CONSTANT_Methodref_info和CONSTANT_InterfaceMethodref_info

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CONSTANT_Fieldref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref_info {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}

4.3 CONSTANT_String_info

1
2
3
4
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
  • string_index
    必须是constant_pool的有效下标,必须指向CONSTANT_Utf8_info结构。

4.4 CONSTANT_Integer_info和CONSTANT_Float_info结构

1
2
3
4
5
6
7
8
CONSTANT_Integer_info {
u1 tag;
u4 bytes;
}
CONSTANT_Float_info {
u1 tag;
u4 bytes;
}
  • bytes
    表达实际值

4.5 CONSTANT_Long_info和CONSTANT_Double_info结构

1
2
3
4
5
6
7
8
9
10
CONSTANT_Long_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double_info {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}

4.6 CONSTANT_NameAndType_info

1
2
3
4
5
CONSTANT_NameAndType_info {
u1 tag;
u2 name_index;
u2 descriptor_index;
}

4.7 CONSTANT_Utf8_info

1
2
3
4
5
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}

4.8 CONSTANT_MethodHandle_info

1
2
3
4
5
CONSTANT_MethodHandle_info {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
  • reference_kind

    The value of the reference_kind item must be in the range 1 to 9. The value denotes the kind of this method handle, which characterizes its bytecode behavior (§5.4.3.5)(Chapter 5: Loading, Linking, and Initializing).

  • reference_index
    必须是constant_pool的有效下标,指向的结构根据reference_kind的不同而有不同的要求:
    • 如果reference_kind为1、2、3、4,必须指向CONSTANT_Fieldref_info结构
    • 如果reference_kind为5、8,必须指向CONSTANT_Methodref_info,而此结构表达了类的方法或构造器
    • 如果reference_kind为6、7,然后
      • 如果class文件的版本号小于52.0,必须指向CONSTANT_Methodref_info结构,此结构表示类的方法;
      • 如果class文件的版本号大于或等于52.0,则必须指向CONSTANT_Methodref_info结构或者CONSTANT_InterfaceMethodref_info结构,表达了类或接口的方法;
    • 如果reference_kind为9,必须指向CONSTANT_InterfaceMethodref_info结构,表达了接口方法。

4.9 CONSTANT_MethodType_info

1
2
3
4
CONSTANT_MethodType_info {
u1 tag;
u2 descriptor_index;
}

4.10 CONSTANT_InvokeDynamic_info

1
2
3
4
5
CONSTANT_InvokeDynamic_info {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}
  • bootstrap_method_attr_index

    The value of the bootstrap_method_attr_index item must be a valid index into the bootstrap_methods array of the bootstrap method table (§4.7.23) of this class file.

5 Fields

1
2
3
4
5
6
7
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

6 Methods

1
2
3
4
5
6
7
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

7 Attributes


1
2
3
4
5
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}

The Code Attribute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Code_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 max_stack;
u2 max_locals;
u4 code_length;
u1 code[code_length];
u2 exception_table_length;
{ u2 start_pc;
u2 end_pc;
u2 handler_pc;
u2 catch_type;
} exception_table[exception_table_length];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
  • max_stack
    给出在方法执行的任意地方操作数栈的最大深度
  • max_locals
    给出方法调用时本地方法表的最大容量
  • code[]
    给出了实现方法的JVM代码的实际字节(byte)。

The BootstrapMethods Attribute

1
2
3
4
5
6
7
8
9
BootstrapMethods_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 num_bootstrap_methods;
{ u2 bootstrap_method_ref;
u2 num_bootstrap_arguments;
u2 bootstrap_arguments[num_bootstrap_arguments];
} bootstrap_methods[num_bootstrap_methods];
}
  • bootstrap_methods[]

8 Format Checking

(TBD)

9 Constraints on Java Virtual Machine Code

(TBD)

10 Verification of class Files

(TBD)

10.1 Verification by Type Checking

10.2 Verification by Type Inference

11 JVM的限制

  • ClassFile结构中16-bit的constant_pool_count限制了per-class或者per-interface的常量池最多只有65535个条目(entries)。这对单个类或接口的总体复杂性起到了内部限制作用。
  • ClassFile结构中的fields_count限制了一个class or interface能声明的field数量不能超过65535。(不包括继承的)
  • 方法数量限制同上。(methods_count
  • 直接父接口的数量限制同上(interfaces_count
  • 方法调用时创建的帧里面,本地变量表中的本地变量数量最多为65535,由Code attribute中的max_locals item所限制,以及由JVM指令集的16-bit本地变量索引所限制。
    其中,longdouble类型视为两个本地变量
  • Code attribute中的max_stack item限制了frame中的操作数栈的大小为65535
    其中,longdouble类型的操作数视为两个单元
  • method descriptor的定义限制了方法参数的数量最多为255
    其中,实例方法的this占了一个单元,longdouble类型的会占两个单元
  • field和方法的名称、field和方法的descriptor以及其他string常量值(包括被ConstantValue attribute引用的)最多为65535byte,由CONSTANT_Utf8_info结构中的16-bit无符号length item所限制
  • 数组的维度最多为255,由multianewarray指令中的opcode dimensions的大小所限制

    The number of dimensions in an array is limited to 255 by the size of the dimensions opcode of the multianewarray instruction and by the constraints imposed on the multianewarray, anewarray, and newarray instructions

Reference