JVM-class文件详解(官方直译)含脑图
获取脑图方式请看最下面!
JVM
类文件(Class文件)结构
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 u4
- value:0xCAFEBABE
minor_version u2
- 0000 暂时不用这两个字节
major_version u2
- 0034 表示版本号为52 表示jdk1.8
constant_pool_count u2
- value:0025 对应10进制397代表常量池中39个常量
constant_pool[constant_pool_count-1] cp_info 常量池,有tag,info[] info[]的值根据tag的值变化而变化,后面0X…表示tag的值
cp_info {
u1 tag;
u1 info[];
}
-
CONSTANT_Utf8_info u1+u2+u1*length 0x01
- tag u1:1
- length u2 bytes中的字节数组长度(不是结果字符串的长度)
- bytes u1 bytes数组包含字符串的字节。
-
CONSTANT_Integer_info u1+u4 0x03
- tag u1:3
- bytes u4 按照高位在前存储的int值,由ASCII转换成16进制获得
-
CONSTANT_float_info u1+u4 0x04
- tag u1:4
- bytes u4 按照高位在前存储的float值,由ASCII转换成16进制获得(IEEE 754 floating-point single format)
-
CONSTANT_Long_info u1+u8 0x05
- tag u1:5
- high_bytes u4
- low_bytes u4
-
CONSTANT_Double_info u1+u8 0x06
- tag u1:6
- high_bytes u4
- low_bytes u4
-
CONSTANT_class_info u1+u2 0x07
- tag u1:7
- name_index u2 指向权限定名常量池utf8的索引
-
CONSTANT_String_info u1+u2 0x08
- tag u1:8
- string_index u2 指向CONSTANT_Utf8_info的索引
-
CONSTANT_Fieldref_info u1+u2+u2 0x09
- tag u1 :9
- class_index u2 可以是class类型也可以是接口类型,指向常量池中的有效索引,类型是CONSTANT_Class_info结构
- name_and_type_index u2 指向字段描述符 CONSTANT_NameAndType_info的索引项(请参考字段描述符)
-
CONSTANT_Methodref_info u1+u2+u2 0x0a
- tag u1:10
- class_index u2 必须是class类型,不是接口类型,
- name_and_type_index u2 指向方法描述符CONSTANT_NameAndType_info的索引项(请参考方法描述符)如果方法名以’<’(’\u003c’)开头,名字必须是特殊的名字(实例初始化会用到),返回类型必须是void
-
CONSTANT_Interface_Methodref_info u5 0x0b
- tag u1:11
- class_index u2 必须是接口类型
- name_and_type_index u2 指向名称及类型描述 符CONSTANT_NameAndType_info的索引项
-
CONSTANT_NameAndType_info u5 0x0c
-
tag u1:12
-
name_index u2 指向该字段或方法名称的CONSTANT_Utf8_info索引
Class文件中变量,方法的名字以非限定名的形式保存的,简单讲就是单纯的变量名或方法名,是不能包含./[;等ASCII字符的。但有个例外
-
descriptor_index u2 指向CONSTANT_Utf8_info结构,代表一个验证的字段描述符或方法描述符
-
-
CONSTANT_MethodHandle_info u5 0x0f
-
tag u1 :15
-
reference_kind u2 决定方法类型,值必须是0- 9,该值表示方法句柄的字节码行为
-
reference_index u2 值必须是常量池的有效索引
-
1.reference_kind=1||2||3||4,指向CONSTANT_Fieldref_info索引
-
2.reference_kind=5||8,指向CONSTANT_Methodref_info索引
-
3.reference_kind=6||7
- 类文件版本<52: 指向CONSTANT_Methodref_info索引
- 类文件版本>=52: 指向CONSTANT_Methodref_info或者CONSTANT_InterfaceMethodref_info索引
-
4.reference_kind=9,指向CONSTANT_InterfaceMethodref_info索引
-
5.reference_kind=8,指向CONSTANT_Methodref_info结构必须是方法
-
-
-
CONSTANT_MethodType_info u3 0x10
- tag u1 :16
- descriptor_index u2 值必须是常量池的有效索 引,常量池在该索引的项必须是CONSTANT_ Utf8_info结构,表示该方法的描述符
-
CONSTANT_InvokeDynamic_info u5 0x12
- tag u1 :18
- bootstrap_method_attr_index u2 当前Class文 件中引导方法表的bootstrap_methods[]数组的 有效索引
- name_and type_index u2 指向名称及类型描述 符CONSTANT_NameAndType_info的索引项
access_flags u2
- ACC_PUBLIC 0001可以被包的类访问
- ACC_FINAL 0010 不允许有子类
- ACC_SUPER 0020 当用到invokespecial指令 时,需要特殊处理的父类方法
- ACC_INTEFACE 0200 标识定义的是接口而不 是类
- ACC_ABSTRACT 0400 不能被实例化,抽象
- ACC_ANNOTATION 2000 标识注解类型
- ACC_ENUM 4000 标识枚举类型
- ACC_SYNTHETIC 1000 标识这个类是否是用户 代码生成。0表示由用户代码生成
this_class u2 :指向一个常量池,一般都指向CONSTANT_class_info类型
super_class u2:指向一个常量池,一般都指向CONSTANT_class_info类型
interfaces_count u2:记录接口的数量,如果为0则不出现interfaces类型
interfaces[interfaces_count] u2:记录具体的接口指向,指向一个常量池对象,一般都指向CONSTANT_class_info类型
fields_count u2:记录字段的数量,如果为0则不出现fields类型
fields[fields_count] field_info:字段表集合
-
access_flags u2:字段访问标志
- 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 u2: 字段名称索引,指向CONSTANT_Utf8_info索引
-
descriptor_index u2:描述符索引,指向CONSTANT_Utf8_info索引
-
字段描述符如何表示
- B byte 字节型
- C char 字符型
- I int 整型
- F float 浮点型
- S short 短整型
- J long 长整型
- D double 双精度浮点型
- Z boolean 布尔型
- L+对象全限定名 对象类型,如:String Ljava/lang/String
- [+基本类型符合 数组类型,如int[] [I
- V void 无类型
-
-
attributes_count u2:属性个数
-
attributes[attributes_count]attribute_info->ConstantValue_attribute 字段表集合
- attribute_name_index u2:属性名称索引,指向CONSTANT_Utf8_info 结构中的“ConstantValue”
- attribute_length u2:值必须是2
- constant_value_index:常量池条目索引必须适合该field
methods_count u2:记录方法的数量,如果是类是一定存在的,如果是接口methods_count可能存在为0,enum 最少4(有默认方法)
methods[methods_count] method_info 方法集合
-
access_flags u2:字段访问标志
- ACC_PUBLIC 0x0001
- ACC_PRIVATE 0x0002
- ACC_PROTECTED 0x0004
- ACC_STATIC 0x0008
- ACC_FINAL 0x0010
- ACC_SYNCHRONIZED 0x0020
- ACC_BRIDGE 0x0040
- ACC_VARARGS 0x0080
- ACC_NATIVE 0x0100
- ACC_ABSTRACT 0x0400
- ACC_STRICT 0x0800
- ACC_SYNTHETIC 0x1000 标志指示此字段是由编译器生成的,不会出现在源代码中。
-
name_index u2:方法名称索引,指向CONSTANT_Utf8_info索引的 or or 有效的非限定名称
-
descriptor_index u2 方法描述索引(返回参数索引),指向CONSTANT_Utf8_info索引
-
attributes_count u2 方法中属性个数
-
attributes attribute_info []
-
Code 执行方法 code_attribute_info
-
attribute_name_index u2 属性名索引,指向CONSTANT_Utf8_info中的“Code”
-
attribute_length u4 属性字节长度,不包括前6字节
-
max_stack u2 操作数栈的最大深度
-
max_locals u2 局部变量的最大数目,包含传入参数的局部变量
- long或double类型的值的最大局部变量索引是max_locals-2,max_locals-1是任何其他类型的值的最大局部变量索引
-
code_length u4 指令长度,表示代码数组中的字节数,必须大于0 小于65536
-
code[code_length] u1*code_length 指令集合
-
exception_table_length 异常计数 u1
-
exception_table[exception_table_length] 异常集合 u8*exception_table_length
- start_pc u2 开始指令地址
- end_pc u2 结束指令地址
- handler_pc u2 异常处理指令地址
- catch_type u2 异常类型,指向CONSTANT_Class_info中catch时抛出的异常类
-
attributes_count u2 Code结构内属性数
-
attributes attronites_info Code结构体内属性集合
-
LinaNumberTable 源码与指令关系 LinaNumberTable_info
-
attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LineNumberTable”
-
attribute_length u4 属性长度,需要去掉初始的6字节
-
line_number_table_length u2 源码指令关系表计数,表示LinaNumberTable的个数
-
line_number_table[line_number_table_ length] u4*line_number_table_length 源码指令关系表数组
- stact_pc u2 开始字节码指令地址
- line_number u2 源码行号
-
-
LocalVariableTable 局部变量描述
-
attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LocalVariableTable”
-
attribute_length u4 属性长度,需要去掉初始的6字节
-
local_variable_table_length u2 局部变量描述计数,表示LocalVariableTable的个数
-
local_variable_table[local_variable_table_ length] u10*local_variable_table_length 局部变量描述表集合 local_variable_ info
- start_pc u2 开始字节码指令地址
- length u2 字节码偏移量
- name_index u2 局部变量名称索引,指向CONSTANT_Utf8_info中的非限定名
- descriptor_index u2 局部变量字段描述符
- index u2 方法执行时,局部变量在栈帧中局部变量表的位置,如果是double,long 它占用index,index+1
-
-
LocalVariableTypeTable 局部变量类型表,方法中使用了泛型变量,则会生成局部变量类型表,对泛型类型的局部变量,需要在LocalVariableTable Attribute和LocalVariableTypeTable Attribute中同时存在一项;而对非泛型类型的局部变量来说,只要在LocalVariableTable Attribute存在表项就可以
如果方法中使用了泛型变量,则会生成 局部变量类型表;局部变量类型表的信息会覆盖掉 局部变量表的信息;JDK5之后才出现的 局部变量类型表,因为JDK5之前不支持泛型,为了兼容以前的老版本,不得不做了这个糟糕的设计;局部变量类型表在Hotspot中基本没有任何作用,仅用于作为Hotspot中的 局部变量表的 signature_cp_index字段赋值。
-
attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ LocalVariableTypeTable”
-
attribute_length u4 属性长度,需要去掉初始的6字节
-
local_variable_type_table_length u2 表示LocalVariableTypeTable的个数
-
local_variable_type_table[local_variable_type_table_length]
- start_pc u2 开始字节码指令地址
- length u2 字节码偏移量
- name_index u2 局部变量名称索引,指向CONSTANT_Utf8_info中的非限定名
- signature_index u2 记录该项代表的局部变量的字段签名,指向CONSTANT_Utf8_info中
- index u2 方法执行时,局部变量在栈帧中局部变量表的位置,如果是double,long 它占用index,index+1
-
-
StackMapTable stack_map_frame 栈图,为了提高JVM在类型检查的验证过程的效率,只用于Class文件加载时的校验
-
attribute_name_index u2 属性名称,指向CONSTANT_Utf8_info中的“ StackMapTable”
-
attribute_length u4 属性长度,需要去掉初始的6字节
-
number_of_entries u2 表示entries表的成员数量
-
entries[number_of_entries] stack_map_frame
-
frame_type
-
same_frame
-
frame_type = SAME ;/ 0-63 /
- 该frame与前一个frame的局部变量区、操作数栈上对应位置的类型都完全一样,这个值也是隐含的 offset_delta,offset_delta=frame_type的值
-
-
same_locals_1_stack_item_frame
-
frame_type = SAME_LOCALS_1_STACK_ITEM; / 64-127 /
- 当前帧与上一帧有相同的局部变量,操作数栈中的变量数目为 1,隐式 offset_delta 为 frame_type - 64
-
verification_type_info stack[1];
-
-
same_locals_1_stack_item_frame_extended
-
frame_type u1= SAME_LOCALS_1_STACK_ITEM_EXTENDED;/* 64-127 */
- 与same_locals_1_stack_item_frame的区别就是offset_delta是明确给定的
-
offset_delta u2
-
verification_type_info stack[1]
-
-
chop_frame
-
frame_type = CHOP/ 248- 250 /
- 当前帧与上一帧具有相同的局部变量,知识不存在最后k个局部变量,并且操作数栈为空。k的值由公式251-frame_type给出,明确给出帧的offset_delta值
-
offset_delta u2
-
-
same_frame_extended
-
frame_type = SAME_FRAME_EXTENDED / 251/
- 局部变量信息和上一个帧相同,且操作数栈为空,与same_frame不同的是offset_delta明确给定的
-
offset_delta u2
-
-
append_frame
-
frame_type = APPEND ; / 252-254 /
- 当前帧比上一帧多了k个局部变量,且操作数栈为空,其中 k = frame_type -251
-
offset_delta u2
-
verification_type_info locals[frame_type - 251]
-
-
full_frame
-
frame_type = FULL_FRAME;/ 255 /
- 局部变量表和操作数栈做完整记录
-
offset_delta
-
number_of_locals
-
verification_type_info locals[number_of_locals]
-
u2 number_of_stack_items
-
verification_type_info stack[number_of_stack_items];
-
-
-
-
-
-
-
Exceptions 抛出异常的方法 Exception_ attribute_info
-
attribute_name_index u2 属性名称,指向名称为Exceptions 的常量池
-
attribute_length u4 属性长度
-
Number_of_exceptions u2 异常数量计数 ,表示有多少个异常名称索引
-
exceptions_index_table[Number_of_ exceptions] u2*Number_of_ exceptions 异常常量池索引
- 每两个字节指向一个CONSTANT_Class_info类型 的常量池,全限定名称
-
-
RuntimeVisibleParameterAnnotations 该方法在运行时可见的修饰该方法参数的Annotation,Java程序可以通过反射机制获取这些Annotation中的值
-
attribute_name_index u2 属性名称,指向名称为RuntimeVisibleParameterAnnotations 的常量池
-
attribute_length u4 属性长度
-
num_parameters u1 记录该方法中的参数个数
-
parameter_annotations[num_parameters] annotation
-
type_index u2 指向CONSTANT_Utf8_info描述符
-
num_element_value_pairs
-
element_value_pairs[num_element_value_pairs] element_value_pairs
- element_name_index,对应注解里字段的字段名称,指向CONSTANT_Utf8_info
- value :加了注解的字段名为 record
-
-
-
RuntimeInvisibleParameterAnnotations 记录该方法在运行时不可见的修饰该方法参数的Annotation 结构与(RuntimeVisibleParameterAnnotations)相同
-
AnnotationDefault
- attribute_name_index u2 属性名称,指向名称为AnnotationDefault 的常量池
- attribute_length u4 属性长度
- default_value 代码注解类型元素的默认值
-
MethodParameters
-
attribute_name_index u2 指向名称为“MethodParameters”的常量池
-
attribute_length u4 属性长度
-
parameters_count u1 参数的数量
-
parameters[parameters_count] parameter
- name_index u2 值必须为0 或者指向常量池中的索引,如果为0 则parameters指向不带名称的形参,如果非0 则必须指向CONSTANT_Utf8_info 中的非限定名
-
-
attributes_count u2 属性表中的属性数量,记录原文件属性信息,一般一个类具有一个
attributes[attributes_count] attribute_info 官方定义为数组,实际上专属类描述的只有
-
SourceFile 记录源文件名称
- attribute_name_index u2 属性名称索引,指向值为“ SourceFile”的常量池
- attribute_length u4 属性长度 值必须为2
- sourcefile_index 源文件名称索引,指向值CONSTANT_Utf8_info 中类地址的常量池
-
InnerClasses 内部类列表
- attribute_name_index u2 属性名称索引,指向值为“ InnerClasses”的常量池
- attribute_length 表示属性的长度,不包括前六个字节。
- number_of_classes 表明classes数组冲的个数
- classes[number_of_classes] 表示一个非包成员的类,都明确对应CONSTANT_Class_info中的一个类
-
EnclosingMethod 仅当一个类为局部类或者匿名类是才能拥有这个属性
- attribute_name_index u2 属性名称索引,指向值为“ EnclosingMethod”的常量池
- attribute_length u4 值必须为4
- class_index u2 指向CONSTANT_Class_info中的
- method_index u2 如果没有实现方法或构造函数的嵌套,则为0 ,否则指向CONSTANT_NameAndType_info的索引,
-
SourceDebugExtension
- attribute_name_index u2 属性名称索引,指向值为“ SourceDebugExtension”的常量池
- attribute_length u4 表示属性的长度,不包括前六个字节。
- debug_extension[attribute_length] u1*attribute_length
-
BootstrapMethods 这个属性用于保存 invokedynamic 指令引用的引导方法限定符
-
attribute_name_index u2 属性名称索引,指向值为“ BootstrapMethods”的常量池
-
attribute_length u4 表示属性的长度,不包括前六个字节。
-
num_bootstrap_methods u2 数组中的引导方法限定符的数量
-
bootstrap_methods[num_bootstrap_methods]
-
bootstrap_method_ref u2
-
num_bootstrap_arguments u2
-
bootstrap_arguments[num_bootstrap_arguments] u2*num_bootstrap_arguments
常量池在该索引处必须是下列结构之一:CONSTANT_String_info、CONSTANT_Class_info、CONSTANT_Integer_info、CONSTANT_Long_info、CONSTANT_Float_info、CONSTANT_Double_info、CONSTANT_MethodHandle_info 或 CONSTANT_MethodType_info
-
-
字段描述符
方法:Object m(int i, double d, Thread t) {…}
方法描述符(IDLjava/lang/Thread;)Ljava/lang/Object;
Constant value attribute types
Field access
XMind: ZEN - Trial Version
关注公众号,每周都有新内容
获取脑图请回复公众号“class文件解析”获取PDF版本脑图,需要补充的知识点可以进行留言,逐步进行完善。
最后感谢大家的关注