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 位量分别通过读取 248 个连续的 8 位字节来构造 多字节数据项总是以 big-endian 顺序存储, 其中高字节排在第一位 在 Java SE 平台中, 此格式由接口 java.io.DataInput 和 java.io.DataOutput 以及类如
java.io.DataInputStream
和
java.io.DataOutputStream
支持
本章定义了自己的一组表示类文件数据的数据类型:
类型 u1,u2 和 u4 分别表示一个无符号的一个, 两个或四个字节数量(即 1 byte2 byte 和 4 byte)
在 Java SE 平台中, 这些类型可以通过接口 java.io.DataInput 的 readUnsignedByte,readUnsignedShort 和 readInt 等方法读取
1 ClassFile 结构
一个 class 文件包含一个单独的 ClassFile 结构:
- 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"role="presentation"style="position: relative;">,minor_version 为 m" role="presentation" style="position: relative;">, 那么我们将 class 文件格式的版本记为 M . m"role="presentation"style="position: relative;">, 因此, 这个版本号可以按字典序排序, 例如 1.5 <2.0 < 2.1" role="presentation" style="position: relative;">
一个 JVM 的实现可以支持的 class 文件格式版本记为 v"role="presentation"style="position: relative;">, 当且仅当 v 落在连续区间 M i .0 v M j . m" role="presentation" style="position: relative;"> 时成立
JVM 实现所遵循的 Java SE 平台的 release level 决定了其支持范围
例如
Oracle 对 JDK release 1.0.2 的 JVM 实现支持的 class 文件格式版本为 [ 45.0 , 45.3 ]"role="presentation"style="position: relative;">
JDK release 1.1.* 支持 [ 45.0 , 45.65535 ]"role="presentation"style="position: relative;">
对于 k 2"role="presentation"style="position: relative;">,JDK release 1. k" role="presentation" style="position: relative;"> 支持范围为 [ 45.0 , 44 + k .0 ]"role="presentation"style="position: relative;">
1.3 constant_pool_count
constant_pool[]中的条目数量 + 1
1.4 constant_pool[]
constant_pool 是一个结构表, 表示 ClassFile 结构及其子结构中引用的各种
字符串常量
类和接口名
字段名
其他常量
每个 constant_pool 表项的格式由第一个标记 (tag) 字节表示
constant_pool 表下标的取值范围是 [ 1 , c o n s t a n t p o o l c o u n t )"role="presentation"style="position: relative;">
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 文件中定义的类或者接口
- 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 结构, 给出对变量的完整描述只包含由此类或者接口声明的变量, 不包括继承而来的
- 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_NATIVE 和 ACC_ABSTRACT 标志都没有在 method_info 里的 access_flags 中设置, 实现此方法的 JVM 指令也要提供
methods[]表达了此 class or intreface 声明的所有方法, 包括实例方法类方法实例初始化方法和 class or interface 初始化方法, 不包括继承而来的方法
- 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[]
- 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
- Object m(int i, double d, Thread t) {...}
描述符为:
- (IDLjava/lang/Thread;)Ljava/lang/Object;
- 4 The Constant Pool
Java 虚拟机指令不依赖于类接口类实例或数组的运行时布局相反, 指令指的是 constant_pool 表中的符号信息
constant_pool 中的所有条目都具有以下的一般结构:
- 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
- CONSTANT_Class_info {
- u1 tag;
- u2 name_index;
- }
tag 的值为
7
, 表示这是一个 CONSTANT_Class,name_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
- 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
- CONSTANT_String_info {
- u1 tag;
- u2 string_index;
- }
- string_index
必须是 constant_pool 的有效下标, 必须指向 CONSTANT_Utf8_info 结构
4.4 CONSTANT_Integer_info 和 CONSTANT_Float_info 结构
- CONSTANT_Integer_info {
- u1 tag;
- u4 bytes;
- }
- CONSTANT_Float_info {
- u1 tag;
- u4 bytes;
- }
- bytes
表达实际值
4.5 CONSTANT_Long_info 和 CONSTANT_Double_info 结构
- 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
- CONSTANT_NameAndType_info {
- u1 tag;
- u2 name_index;
- u2 descriptor_index;
- }
- 4.7 CONSTANT_Utf8_info
- CONSTANT_Utf8_info {
- u1 tag;
- u2 length;
- u1 bytes[length];
- }
- 4.8 CONSTANT_MethodHandle_info
- 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 为 1234, 必须指向
CONSTANT_Fieldref_info
结构
如果 reference_kind 为 58, 必须指向
CONSTANT_Methodref_info
, 而此结构表达了类的方法或构造器
如果 reference_kind 为 67, 然后
如果 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
- CONSTANT_MethodType_info {
- u1 tag;
- u2 descriptor_index;
- }
- 4.10 CONSTANT_InvokeDynamic_info
- 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
- field_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
- attributes[]
里面的每个 item 都必须是 attribute_info 结构
- 6 Methods
- method_info {
- u2 access_flags;
- u2 name_index;
- u2 descriptor_index;
- u2 attributes_count;
- attribute_info attributes[attributes_count];
- }
- attributes[]
里面的每个 item 都必须是 attribute_info 结构
- 7 Attributes
- attribute_info {
- u2 attribute_name_index;
- u4 attribute_length;
- u1 info[attribute_length];
- }
- The Code Attribute
- 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
- 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[]
- bootstrap_method_ref
其值必须是 constant_pool 中的有效下标, 指向的必须是
CONSTANT_MethodHandle_info
结构
- 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 本地变量索引所限制
其中, long 和 double 类型视为两个本地变量
Code attribute 中的 max_stack item 限制了 frame 中的操作数栈的大小为 65535
其中, long 和 double 类型的操作数视为两个单元
method descriptor 的定义限制了方法参数的数量最多为 255
其中, 实例方法的 this 占了一个单元, long 和 double 类型的会占两个单元
field 和方法的名称 field 和方法的 descriptor 以及其他 string 常量值 (包括被 ConstantValue attribute 引用的) 最多为 65535 个 byte, 由 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
The Java® Virtual Machine Specification - Java SE 8 Edition
来源: https://juejin.im/entry/5aa6473a51882555635df6b8