Java Class文件解析
一、描述
Class文件是一组以8位(1字节)为基础单位的二进制流。
当数据项大于8位时,按照【高位在前】分割成若干个8位进行存储。
按照Java虚拟机规范的规定,Class文件结构只有两种数据类型:无符号数和表
二、无符号数
无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1字节,2字节,4字节,8字节的无符号数。
无符号数可用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值。
三、表
类型 | 名字 | 名称 | 数量 | 描述 |
u4 | magic | 魔数 | 1 | Class文件1-4字节,是否能被JVM接受,更加安全 |
u2 | minor_version | 次版本号 | 1 | Class文件5-6字节 |
u2 | major_version | 主版本号 | 1 | Class文件7-8字节(52对应JDK1.8) |
u2 | constant_pool_count | 常量池大小 | 1 | 从1开始,第0项常量为空:不引用任何一个常量池项目 |
cp_info | constant_pool | 常量池 | constant_pool_count - 1 |
字面量:字符串、常量值等 符号引用:类和接口的全限定名;字段名称和描述符;方法名称和描述符 |
u2 | access_flag | 类访问标志 | 1 | ACC_PUBLIC |
u2 | this_class | 类索引 | 1 | 确定类的全限定名 |
u2 | super_class | 父类索引 | 1 | 确定类的父类的全限定名(除Object,所有类的父类索引不为0) |
u2 | interfaces_count | 接口数量 | 1 | 确定接口数量 |
u2 | interfaces | 接口索引集合 | interfaces_count | 确定类实现了那些接口;如果数量为0,则不占用任何字节 |
u2 | fields_count | 字段数量 | 1 | 确定字段数量 |
field_info | fields | 字段集合 | fields_count | 描述接口或类中声明的表量;类变量、实例表量 |
u2 | methods_count | 方法数量 | 1 | 确定方法数量 |
method_info | methods | 方法集合 | methods_count | 描述接口或者类中方法 |
u2 | attributes_count | 属性数量 | 1 | 确定属性数量 |
attribute_info | attributes | 属性集合 | attributes_count | 描述属性 |
3.1 常量池项目
常量 | 项目 | 类型 | 描述 |
CONSTANT_Utf8_info | tag | u1 | 1 |
length | u2 | 字符串字节数(UTF-8编码) | |
bytes | u1 | 字符串(UTF-8编码) | |
CONSTANT_Integer_info | tag | u1 | 3 |
bytes | u4 | int(高位在前) | |
CONSTANT_Float_info | tag | u1 | 4 |
bytes | u4 | float(高位在前) | |
CONSTANT_Long_info | tag | u1 | 5 |
bytes | u8 | long(高位在前) | |
CONSTANT_Double_info | tag | u1 | 6 |
bytes | u8 | double(高位在前) | |
CONSTANT_Class_info | tag | u1 | 7 |
index | u2 | 指向全限定名常量项的索引(CONSTANT_Utf8_info) | |
CONSTANT_String_info | tag | u1 | 8 |
index | u2 | 指向字符串字面量的索引(CONSTANT_Utf8_info) | |
CONSTANT_Fieldref_info | tag | u1 | 9 |
index | u2 | 指向声明字段的类或接口描述符的索引(CONSTANT_Class_info) | |
index | u2 | 指向字段描述符的索引(CONSTATN_NameAndType_info) | |
CONSTANT_Methodref_info | tag | u1 | 10 |
index | u2 | 指向声明方法的类描述符的索引(CONSTANT_Class_info) | |
index | u2 | 指向方法的名称及类型描述符的索引(CONSTANT_NameAndType_info) | |
CONSTANT_InterfaceMethodref_info | tag | u1 | 11 |
index | u2 | 指向声明方法的接口描述符的索引(CONSTANT_Class_info) | |
index | u2 | 指向方法的名称及类型描述符的索引(CONSTANT_NameAndType_info) | |
CONSTANT_NameAndType_info | tag | u1 | 12 |
index | u2 | 指向字段或方法名称常量项的索引(CONSTANT_Utf8_info) | |
index | u2 | 指向字段或方法描述符常量项的索引(CONSTANT_Utf8_info) | |
CONTANT_MethodHandle_info | tag | u1 | 15 |
reference_kind | u1 | 1-9;决定方法句柄类型;标识方法句柄的字节码行为 | |
reference_index | u2 | 对常量池的有效索引 | |
CONSTANT_MethodType_info | tag | u1 | 16 |
descriptor_index | u2 | 对常量池的有效索引,方法的描述符(CONSTANT_Utf8_info) | |
CONSTANT_InvokeDynamic_info | tag | u1 | 18 |
bootstrap_method _attr_index |
u2 | 对当前Class文件中引导方法的bootstrap_methods[]数组的索引 | |
name_and_type_ index |
u2 |
对当前常量池的有效索引,方法名称和方法描述符 (CONSTANT_NameAndType_info) |
3.2 描述符标识字段含义
标识字符 | 含义 |
B | 基本数据类型(byte) |
C | 基本数据类型(char) |
D | 基本数据类型(double) |
F | 基本数据类型(float) |
I | 基本数据类型(int) |
J | 基本数据类型(long) |
S | 基本数据类型(short) |
Z | 基本数据类型(boolean) |
V | 特殊类型(void) |
L | 对象类型(Ljava/lang/Object)([[Ljava/lang/Object) |
3.3类访问标志
标志名称 | 标志值 | 含义 |
ACC_PUBLIC | 0x0001 | 是否是public类型 |
ACC_FINAL | 0x0010 | 是否是final类型(类) |
ACC_SUPER | 0x0020 |
是否允许使用invokespecial字节码指令的新语意 (JDK 1.0.2之后编译出来的类为真) |
ACC_INTERFACE | 0x0200 | 标识接口 |
ACC_ABSTRACT | 0x0400 | 是否是abstract类型(接口和抽象类为真) |
ACC_SYNTHETIC | 0x1000 | 标识类不由用户生成 |
ACC_ANNOTATION | 0x2000 | 标识注解 |
ACC_ENUM | 0x4000 | 标识枚举 |
3.4.1 字段表集合
类型 | 名称 | 数量 | 备注 |
u2 | access_flags | 1 | 字段访问标志 |
u2 | name_index | 1 | 字段简单名称(CONSTANT_Utf8_info) |
u2 | descriptor_index | 1 | 字段的描述符(CONSTANT_Utf8_info) |
u2 | attributes_count | 1 | 属性数量 |
attribute_info | attributes | attributes_count | 字段访问标志的集合 |
3.4.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_SYNTHEIC | 0x1000 | 字段是否由编译器自动产生 |
ACC_ENUM | 0x4000 | 字段是否enum |
3.5.1 方法表集合
类型 | 名称 | 数量 | 备注 |
u2 | access_flags | 1 | 方法访问标志(ACC_PUBLIC) |
u2 | name_index | 1 | 方法简单名称(CONSTANT_Utf8_info) |
u2 | desciptor_index | 1 | 方法的描述符(CONSTANT_Utf8_info) |
u2 | attributes_count | 1 | 属性数量 |
attribute_info | attributes | attributes_count | 属性集合 |
3.5.2 方法访问标志
标志名称 | 标志值 | 含义 |
ACC_PUBLIC | 0x0001 | 方法是否public |
ACC_PRIVATE | 0x0002 | 方法是否private |
ACC_PROTECTED | 0x0004 | 方法是否protected |
ACC_STATIC | 0x0008 | 方法是否static |
ACC_FINAL | 0x0010 | 方法是否final |
ACC_SYNCHRONIZED | 0x0020 | 方法是否synchronized |
ACC_BRIDGE | 0x0040 | 方法是否由编译器产生的桥接方法 |
ACC_VARARGE | 0x0080 | 方法是否接受不定参数 |
ACC_NATIVE | 0x0100 | 方法是否native |
ACC_ABSTRACT | 0x0400 | 方法是否abstract |
ACC_STRICTFP | 0x0800 | 方法是否strictfp |
ACC_SYNTHETIC | 0x1000 | 方法是否由编译器自动产生 |
3.6 属性表
3.6.1 Code属性
类型 | 名称 | 数量 | 备注 |
u2 | attribute_name_index | 1 | 属性名称索引(CONSTANT_Utf8_info) |
u4 | attribute_length | 1 | 属性长度 |
u2 | max_stack | 1 | |
u2 | max_locals | 1 | |
u4 | code_length | 1 | |
u1 | code | code_length | |
u2 | exception_table_length | 1 | |
exception_info | exception_table | exception_table_length | |
u2 | attributes_count | 1 | |
attribute_info | attributes | attributes_count |
3.6.2 Exception
类型 | 名称 | 数量 | 备注 |
u2 | attribute_name_index | 1 | |
u4 | attribute_length | 1 | |
u2 | number_of_exceptions | 1 | 异常数量 |
u2 | exception_index_table | number_of_exception | 异常(CONSTANT_Class_info) |