JVM 类结构
1概述
1.1类文件格式不是必须存在于文件里。
1.2多字节数据项必须严格按照大端在前(big-endian)顺序进行存储(Multibyte data items are always stored in big-endian order,where the high bytes come first)
1.3 Class文件是一组以8字节为基础单位的二进制流,各个数据项严格按照顺序紧凑排列,没有任何分隔符
1.4Class文件格式采用一种类似C语言结构体的伪结构(This chapter presents the class file format using pseudostructures written in a C-like structure notation),只有两种数据类型:无符号数(unsigned)和表(table)
1.5无符号数是基本的数据类型,可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值,以u1,u2,u4,u8来分别代表1个字节,2个字节,4个字节,8个字节
1.6表由多个无符号数或其他表作为数据项构成的复合数据类型
1.7当描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式,这时候称这一系列连续的某一类型的数据为某一类型的集合
2、类结构元素
类型 | 数量 | 说明 | |
u4 | 1 | 魔数(magic),确定是否为虚拟机所接受的类文件,固定值为0xCAFEBABE | |
u2 | 1 | 副版本号(minor_version) 1、主版本号为45-55时,副版本号可以为任何值 2、从主版本号56(jdk12)开始,副版本号必须为0或65535 3、当副版本号为65535时,为预览版 | |
u2 | 1 | 主版本号(major_version), 1、值从45开始 2、即使文件格式无任何变化,虚拟机也必须拒绝执行类主版本号超过虚拟机版本号的文件。 | |
u2 | 1 | constant_pool_count;常量池计数器 | |
cp_info | constant_pool[constant_pool_count-1] | 常量池 1、是一种表结构 2、以1~constant_pool_count-1为索引 3、第一个字节作为类型标记,这个字节称为标签字节(tag byte) 4、主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References) 5、通用格式: cp_info { u1 tag; u1 info[]; } | |
u2 | 1 | access_flags;访问标志, 1、一种由标志构成的掩码 The value of the access_flags item is a mask of flags used to denote access permissions to and properties of this class or interface 2、取值以及含义参考本章第4节 3、没有使用到的标志位都为0 | |
u2 | 1 | this_class;类索引 1、取值为常量池有效的索引值 2、常量池中索引处的成员必须为CONSTANT_Class_info类型 | |
u2 | 1 | super_class;父类索引 1、Java不允许多重继承,所以父类索引只有一个 2、取值要么为0,要么是常量池中某个有效索引值 3、当值为0,此类只能用于表示Object类 4、当值不为0,常量池中索引处的成员必须为CONSTANT_Class_info类型 5、所有父类的access_flags,均不能带有ACC_FINAL标志 Neither the direct superclass nor any of its superclasses may have the ACC_FINAL flag set in the access_flags item of its ClassFile structure. | |
u2 | 1 | interfaces_count;接口索引计数器,如果没有接口,则取值0 | |
u2 | interfaces[interfaces_count] | 接口集合 1、每个元素值都是常量池中某个有效索引值 2、按implements关键字后面的接口,从左到右排列 | |
u2 | 1 | fields_count;字段计数器 | |
field_info | fields[fields_count] | 字段表 1、每个成员都是field_info结构,参考2.4 2、包括类变量和实例变量 3、不包括方法内声明的局部变量 4、不包括从父类或父接口继承的那些字段 | |
u2 | 1 | methods_count;方法计数器 | |
method_info | methods[methods_count] | 1、每个成员都是method_info结构,参考本章第7节 2、方法表只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法 3、支持方法访问权限(access_flags)既不是ACC_NATIVE又不是ACC_ABSTRACT | |
u2 | 1 | attributes_count;属性计数器 | |
attribute_info | attributes[attributes_count] | 1、每个成员都是attribute_info结构,参考2.6 |
3、常量池(constant_pool)
3.1基本格式
字段 | 类型 | 说明 |
tag | u1 | 类型 |
info[] | u1 |
3.2常量池类型(tag)
类型 | tag | 类文件版本 | 首次javaSE版本 | 说明 |
CONSTANT_Utf8 | 1 | 45.3 | 1.0.2 | UTF-8编码的字符串 |
CONSTANT_Integer | 3 | 45.3 | 1.0.2 | 整型字面量 |
CONSTANT_Float | 4 | 45.3 | 1.0.2 | 浮点型字面量 |
CONSTANT_Long | 5 | 45.3 | 1.0.2 | 长整型字面量 |
CONSTANT_Double | 6 | 45.3 | 1.0.2 | 双精度浮点型字面量 |
CONSTANT_Class | 7 | 45.3 | 1.0.2 | 类或接口的索引 |
CONSTANT_String | 8 | 45.3 | 1.0.2 | 字符串类型字面量 |
CONSTANT_Fieldref | 9 | 45.3 | 1.0.2 | 字段的符号引用 |
CONSTANT_Methodref | 10 | 45.3 | 1.0.2 | 类中方法的符号引用 |
CONSTANT_InterfaceMethodref | 11 | 45.3 | 1.0.2 | 接口中方法的符号引用 |
CONSTANT_NameAndType | 12 | 45.3 | 1.0.2 | 字段或方法的部分符号引用 |
CONSTANT_MethodHandle | 15 | 51 | 7 | 表示方法具柄 |
CONSTANT_MethodType | 16 | 51 | 7 | 方法类型 |
CONSTANT_InvokeDynamic | 18 | 51 | 7 | 表示一个动态方法调用点 |
CONSTANT_Module | 19 | 53 | 9 | 表示一个模块 |
CONSTANT_Package | 20 | 53 | 9 | 表示一个模块中开放或者导出的包 |
CONSTANT_Dynamic | 17 | 55 | 11 | 表示一个动态计算常量 |
3.3常量池数据类型的结构
类型 | 字段 | 类型 |
CONSTANT_Utf8 | tag | u1 |
length | u2 | |
bytes[] | u1 | |
CONSTANT_Integer | tag | u1 |
bytes | u4 | |
CONSTANT_Float | tag | u1 |
bytes | u4 | |
CONSTANT_Long | tag | u1 |
high_bytes | u4 | |
low_bytes | u4 | |
CONSTANT_Double | tag | u1 |
high_bytes | u4 | |
low_bytes | u4 | |
CONSTANT_Class | tag | u1 |
name_index | u2 | |
CONSTANT_String | tag | u1 |
string_index | u2 | |
CONSTANT_Fieldref | tag | u1 |
class_index | u2 | |
name_and_type_index | u2 | |
CONSTANT_Methodref | tag | u1 |
class_index | u2 | |
name_and_type_index | u2 | |
CONSTANT_InterfaceMethodref | tag | u1 |
class_index | u2 | |
name_and_type_index | u2 | |
CONSTANT_NameAndType | tag | u1 |
name_index | u2 | |
descriptor_index | u2 | |
CONSTANT_MethodHandle | tag | u1 |
reference_kind | u2 | |
reference_index | u2 | |
CONSTANT_MethodType | tag | u1 |
descriptor_index | u2 | |
CONSTANT_InvokeDynamic | tag | u1 |
bootstrap_method_attr_index | u2 | |
name_and_type_index | u2 | |
CONSTANT_Module | tag | u1 |
name_index | u2 | |
CONSTANT_Package | tag | u1 |
name_index | u2 | |
CONSTANT_Dynamic | tag | u1 |
bootstrap_method_attr_index | u2 | |
name_and_type_index | u2 |
4类访问标志(access_flags)
标志 | 值 | 说明 |
ACC_PUBLIC | 0x0001 | public |
ACC_FINAL | 0x0010 | final,不能与ACC_ABSTRACT同时设置 |
ACC_SUPER | 0x0020 | 是否使用invokespecial指令的新语义,因为invokespecial指令在jdk1.0.2以后做了改变,所以在jdk1.0.2之后,这里都为真 |
ACC_INTERFACE | 0x0200 | 接口,设置了此值,ACC_ABSTRACT必须同时设置 ACC_FINAL, ACC_SUPER, ACC_ENUM和 ACC_MODULE,必须不能设置 |
ACC_ABSTRACT | 0x0400 | 抽象类,不能实例化 |
ACC_SYNTHETIC | 0x1000 | 标志该类或接口是由编译器生成 |
ACC_ANNOTATION | 0x2000 | 声明为注解,同时必须设置ACC_SYNTHETIC |
ACC_ENUM | 0x4000 | 声明为枚举 |
ACC_MODULE | 0x8000 | 声明为模块,如果这个值被设置,则不能有其他标志被设置 If the ACC_MODULE flag is set in the access_flags item, then no other flag in the access_flags item may be set |
5字段表结构(field_info)
5.1基础结构
字段 | 类型 | 说明 |
access_flags | u2 | 访问标志,参考2.4.2 |
name_index | u2 | 字段简单名称,指向常量池一个CONSTANT_Utf8_info值的索引 |
descriptor_index | u2 | 字段的描述符,指向常量池一个CONSTANT_Utf8_info值的索引 |
attributes_count | u2 | 参考2.7 |
attributes[attributes_count] | attribute_info | 参考2.7 |
5.2字段访问标志
标志 | 值 | 说明 |
ACC_PUBLIC | 0x0001 | public |
ACC_PRIVATE | 0x0002 | private |
ACC_PROTECTED | 0x0004 | protected |
ACC_STATIC | 0x0008 | static |
ACC_FINAL | 0x0010 | final |
ACC_VOLATILE | 0x0040 | volatile |
ACC_TRANSIENT | 0x0080 | transient |
ACC_SYNTHETIC | 0x1000 | 标志该字段是由编译器生成,如果字段存在这个标志,则不能有其他任何访问标志 |
ACC_ENUM | 0x0001 | 枚举 |
a ACC_PUBLIC、ACC_PRIVATE、ACC_PROTECTED三选一
b ACC_FINAL、ACC_VOLATILE二选一
c接口中的字段必须有ACC_PUBLIC,ACC_STATIC,ACC_FINAL,三个标志
6方法结构(method_info)
6.1基础结构
字段 | 类型 | 说明 |
access_flags | u2 | 访问标志,参考本章6.2 |
name_index | u2 | 字段简单名称,指向常量池一个CONSTANT_Utf8_info值的索引,必须是有效的非限定名称,或者<init>,或者<clinit> |
descriptor_index | u2 | 字段的描述符,指向常量池一个CONSTANT_Utf8_info值的索引, 1、当是类的<init>方法,必须描述为void方法 2、当类名是<clinit>,必须描述为void方法,且jdk7以后,此方法无参数 |
attributes_count | u2 | 参考2.7 |
attributes[attributes_count] | attribute_info | 参考2.7 |
6.2方法访问标志
标志 | 值 | 说明 | |
ACC_PUBLIC | 0x0001 | public | |
ACC_PRIVATE | 0x0002 | private | |
ACC_PROTECTED | 0x0004 | protected | |
ACC_STATIC | 0x0008 | static,jdk7以后<clinit>方法必须有此标志 | |
ACC_FINAL | 0x0010 | final | |
ACC_SYNCHRONIZED | 0x0020 | synchronized | |
ACC_BRIDGE | 0x0040 | 桥接方法,为了泛型方法兼容jdk1.5以前版本,编译器自动生成 | |
ACC_VARARGS | 0x0080 | 有可变长参数的标志 | |
ACC_NATIVE | 0x0100 | native | |
ACC_ABSTRACT | 0x0400 | abstract | |
ACC_STRICT | 0x0800 | ||
ACC_SYNTHETIC | 0x1000 |
a ACC_PUBLIC, ACC_PRIVATE,ACC_PROTECTED 必须三选一
b jdk8以前,接口的方法必须有ACC_PUBLIC 和ACC_ABSTRACT标志
c jdk8以及以后,接口的方法必须ACC_PUBLIC , ACC_PRIVATE二选一
d 方法如果标记了ACC_ABSTRACT,则不能有ACC_PRIVATE, ACC_STATIC, ACC_FINAL,ACC_SYNCHRONIZED, ACC_NATIVE, ACC_STRICT标记
e实例的初始化方法只能ACC_PUBLIC, ACC_PRIVATE,ACC_PROTECTED三选一,以及ACC_VARARGS, ACC_STRICT, ACC_SYNTHETIC可选,不能有其他标志
f实例或接口的方法被隐式调用,只能设置ACC_STATIC 和 ACC_STRICT标志
7属性结构(attribute_info)
7.1基本结构
字段 | 类型 | 说明 |
attribute_name_index | u2 | 指向常量池一个CONSTANT_Utf8_info值的索引 |
attribute_length | u4 | 属性长度,长度不包括自身和attribute_name_index的长度 |
info[attribute_length] | u1 |
7.2属性类型
属性 | 位置 | 首次版本 |
ConstantValue | field_info | 45.3 |
Code | method_info | 45.3 |
Exceptions | method_info | 45.3 |
SourceFile | classFile | 45.3 |
LineNumberTable | code | 45.3 |
LocalVariableTable | code | 45.3 |
InnerClasses | classFile | 45.3 |
Synthetic | classFile field_info method_info | 45.3 |
Deprecated | classFile field_info method_info | 45.3 |
EnclosingMethod | classFile | 49 |
Signature | classFile field_info method_info | 49 |
SourceDebugExtension | classFile | 49 |
LocalVariableTypeTable | code | 49 |
RuntimeVisibleAnnotations | classFile field_info method_info | 49 |
RuntimeInvisibleAnnotations | classFile field_info method_info | 49 |
RuntimeVisibleParameterAnnotations | method_info | 49 |
RuntimeInvisibleParameterAnnotations | method_info | 49 |
AnnotationDefault | method_info | 49 |
StackMapTable | code | 50 |
BootstrapMethods | classFile | 51 |
RuntimeVisibleTypeAnnotations | classFile field_info method_info code | 52 |
RuntimeInvisibleTypeAnnotations | classFile field_info method_info code | 52 |
MethodParameters | method_info | 52 |
Module | classFile | 53 |
ModulePackages | classFile | 53 |
ModuleMainClass | classFile | 53 |
NestHost | classFile | 55 |
NestMembers | classFile | 55 |
7.3属性类型结构