今天主要记录一下JVMS中定义的标准class文件的结构1。
Class文件是一组以8位字节为基础单位的二进制流,每部分都严格按照规范中的顺序出现,中间不会出现任务分隔符。对于所有占用非8字节数据项出现时,则会按高为到地位顺序进行分割进而进行存储。
##类文件结构
一个类文件都包含一下一个类文件结构,在类文件中使用类C符号结构就行表示。我们可以使用表(tables)和项(items)来描述类文件格式,表是有0个或者多个大小可变的项和表组成。具体类文件结构为:
类型 | 名称 | 注释 |
---|---|---|
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 | intefaces[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 number: identify the class file format,value is 0xCAFEBABE
-
minor-version, major-version:class文件的次版本号和主版本号,两者在一起决定当前class文件的版本号为major.minor,具体jdk版本号则从45开始,jdk1.1之后的每个大版本发布主版本号向上加1
-
constant_pool_count:常量池入口,是常量表中常量数加1
-
constant_pool:常量池,索引值从1开始到从常量数-1结束,此处空出0是为了满足后面某些指向常量池的索引值的数据在特定情况下需要表达“不引用任何一个常量池项”的意思。
-
access_flags:访问标志,用于识别类或接口层次的访问信息,具体访问标志位及含义如下–
标志名称|标志值|含义
----|----|----
ACC_PUBLIC|0x0001|是否是public类型
ACC_FINAL|0x0010|是否被声明为final,只有类可以设置
ACC_SUPER|0x0020|是否允许使用invokespecial字节码指令,jdk1.2之后此字段编译出来为true
ACC_INTERFACE|0x0200|标识这是一个接口
ACC_ABSTRACT|0x0400|是否是一个抽象类型,接口和抽象类此标志为true,其他类为false
ACC_SYNTHETIC|0x1000|标识这个类并非是有用户代码生成的
ACC_ANNOTATION|0x2000|标识这是一个注解
ACC_ENUM|0x4000|标识这是一个枚举 -
this_class:类索引,值指向常量池中的一个有效的Constant_Class_Info
-
super_class:父类索引,如果是类且值为0,则必须是Object类
-
interfaces_count:接口集合中接口数
-
interfaces:这个类实现了哪些接口,按源码中从左到右顺序依次列出
-
fields_count:描述字段表大小
-
fields:字段表用于描述接口或类中定义的变量,包括类级变量或实例级变量,其中每个变量结构为一个field_info
-
methods_count:描述方法表大小
-
methods:是一个类或接口中定义的方法的完整描述,方法表中每个变量结构为一个method_info,其中不包含从父类继承或者接口实现的方法
-
attributes_account:描述属性表大小
###constant_pool
####1.常量池中主要分为两大类常量 -
字面量(Literal):
-
符号引用(Symbolic References):主要包括一下三类–
-
类和接口的全限定名(Fully Qualified Name):主要是针对类名和接口名, 其中类/接口名中的‘/’的由‘.’代替,eg:Thread类名java.lang.Thread会使用一个CONSTANT_Utf8_Info表示为java/lang/Thread
-
字段的名称和描述符(Descriptor)
主要包括三种:BaseType(B C D F I J S Z)、ObjectType(L)、ArrayType([) -
方法的名称和描述符:按照先参数列表,后返回值的顺序描述,参数列表按照严格的参数顺序放在一组小括号内(),即( {ParameterDescriptor} ) ReturnDescriptor,eg:Object m(int i, double d, Thread t) {…}
可记录为(IDLjava/lang/Thread;)Ljava/lang/Object。
具体字段类型(FieldType)讨论如下:
标识字符 | 对应类型 | 描述 |
---|---|---|
B | byte | |
C | char | |
D | double | |
F | float | |
I | int | |
J | long | |
L | reference | 对象类型,eg:Ljava/lang/Object |
S | short | |
Z | boolean | |
V | void | |
[ | reference | 数组类型,eg:java.lang.String[][]数组可记录为[[java/lang/String |
####2.在常量池中常量都有一个统一的格式:
cp_info{
: u1 tag;
: u1 info[];
}
tag类型:
Structure | ConstantType | Value | 描述 |
---|---|---|---|
Constant_utf-8_info | constant_utf-8 | 1 | UTF-8编码的字符串 |
Constant_integer_info | constant_integer | 3 | 整型字面量 |
Constant_float_info | constant_float | 4 | 浮点型字面量 |
Constant_long_info | constant_long | 5 | 长整形字面量 |
Constant_double_info | constant_double | 6 | 双精度浮点型字面量 |
Constant_class_info | constant_class | 7 | 类或接口的符号引用 |
Constant_string_info | constant_string | 8 | 字符串字符量 |
Constant_fieldRef_Info | constant_fieldRef | 9 | 字段的字符引用 |
Constant_methodRef_info | constant_methodRef | 10 | 类中方法的字符引用 |
Constant_interfaceMethodref_info | constant_interfaceMethodref | 11 | 接口中方法的字符引用 |
Constant_nameAndType_info | constant_nameAndType | 12 | 字段或方法的部分字符引用 |
Constant_MethodHandle_info | constant_MethodHandle | 15 | |
Constant_methodType_info | constant_methodType | 16 | |
Constant_invokeDynamic_info | constant_invokeDynamic | 18 |
对于常量池中以上类型的结构如下:
- 对于constant_class _info、constant_string_info有相同的结构
{ u1 tag; u2 name_index};
其中name_index是常量池中的一个constant_utf-8_info - 对于constant_fieldRef_info、constant_methodRef_info、constant_interfaceMethodRef_info有相同的结构:
{u1 tag; u2 class_index; u2 name_and_type_index; }
其中class_index必须是常量池中的一个constant_class_info,name_and_type_index必须是常量池中的一个constant_nameAndType_info - 对于Constant_integer_info、Constant_float_info有相同的结构
{ u1 tag; u4 bytes; } - 对于Constant_long_info、Constant_double_info有相同的结构
{u1 tag; u4 high_bytes; u4 low_bytes; } - constant_nameAndType_info {u1 tag; u2 name_index; u2 descriptor_index; }
其中name_index和descriptor_index都是指向常量池中的一个constant_utf-8_info,不同的是name_index表示的是一个字段或方法常量项,而descriptor_index表示的是一个字段或方法描述符 - constant_utf-8_info{ u1 tag; u2 length; u1 bytes[length]; }
###Fields
filed_info结构为{
: u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
-
access_flags访问权限标识名称和值对应如下:
标识名称|值|描述
—|----|-----
ACC_PUBLIC|0x0001|
ACC_PRIVATE|0x0002|
ACC_PROTECTED|0x0004|
ACC_STATIC|0x0008|
ACC_FINAL|0x0010|
ACC_VOLATILE|0x0040|
ACC_TRANSIENT|0x0080|
ACC_SYNTHETIC|0x1000|是否由编译器自动产生,不存在于源码中
ACC_ENUM|0x4000| -
name_index:指向常量池中一个constant_utf-8_info,标识一个字段的非限定名称
-
descriptor_index:指向常量池中一个constant_utf-8_info,标识一个字段的描述符
-
attributes[attributes_account]:指向一个attribute_info结构
###Methods
methods_info结构为:
{u2 access_flags; u2 name_index; u2 descriptor_index; u2 attributes_account; attribute_info attributes_info[attributes_account]}
标识名称 | 值 | 描述 |
---|---|---|
ACC_PUBLIC | 0x0001 | |
ACC_PRIVATE | 0x0002 | |
ACC_PROTECTED | 0x0004 | |
ACC_STATIC | 0x0008 | |
ACC_FINAL | 0x0010 | |
ACC_SYNCHRONIZED | 0x0020 | |
ACC_BRIDGE | 0x0040 | A bridge method, generated by the compiler. |
ACC_VARARGS | 0x0080 | 方法是否接受不定参数 |
ACC_NATIVE | 0x0100 | |
ACC_ABSTRACT | 0x0400 | |
ACC_STRICT | 0x0800 | |
ACC_SYNTHETIC | 0x1000 | Declared synthetic; not present in the source code. |
- name_index:指向常量池中一个constant_utf-8_info,只能是一个非限定名称或是和
- 其他几项同字段表中诸项.
###Attributes
attribute_info通用结构为:{
: u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}
- attribute_name_index标识属性名,是一个16位的无符号数,指向常量池中的一个constant_utf-8_info
- attribute_length表示属性信息字节子序列的长度,不包括attribute_name_index和attribute_length这六位
- 在jvms8中预定义了23种虚拟机能识别的属性规范,主要看常见的在jvms第二版中定义的9种类型:
属性名称|使用位置|描述
—|---|–
Code|方法表|Java代码编译成的字节码指令
ConstantValue|字段表|final关键字定义的常量值
Deprecated|字段表、方法表、类|定义为deprecated的方法和字段
Exceptions|方法表|方法抛出的异常
InnerClass|类|内部类
LineNumberTable|code属性|Java源码的行号和字节码的对应关系
LocalVariableTable|code属性|方法的局部变量描述
SourceFile|类文件|源文件名称
Synthetic|字段表、方法表、类|表示方法或字段为编译器自动生成的
在类文件中有自己的数据类型集:u1,u2,u4(代表着1,2,4字节的无符号数)
jvms中class file format
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html ↩︎