无符号数:用来描述数字,索引引用,数量值和按UTF-8编码构成的字符串值; 表:由多个无符号数或者其他表作为数据项构成的复合数据类型,表名基本以_info结尾
1) 魔数(0xCAFEBABE)4个字节;
次版本号(第5,6个字节),主版本号(第7,8个字节)
| JDK版本号 | Class版本号 | 16进制 |
| 1.1 | 45.0 | 00 00 00 2D |
| 1.2 | 46.0 | 00 00 00 2E |
| 1.3 | 47.0 | 00 00 00 2F |
| 1.4 | 48.0 | 00 00 00 30 |
| 1.5 | 49.0 | 00 00 00 31 |
| 1.6 | 50.0 | 00 00 00 32 |
| 1.7 | 51.0 | 00 00 00 33 |
| 1.8 | 52.0 | 00 00 00 34 |
2) 常量池(入口u2数据类型表示常量池的容量计数,唯独此容量计数从1开始,0表示不引用任何一个常量池项目).常量池主要存放两大类常量:
1) 字面量:如文本字符串和被声明为final的常量
2) 符号引用:如被模块导出或者开放的包;类和接口的全限定名;字段名称和描述符;方法名 称和描述符;方法句柄和方法类型;动态调用点和动态常量;
常量表的项目类型
| 类型 | 标志 | 描述 |
| CONSTANT_Utf8_info | 1 | UTF-8编码的字符串 |
| CONSTANT_Integer_info | 3 | 整型字面量 |
| CONSTANT_Float_info | 4 | 浮点型字面量 |
| CONSTANT_Long_info | 5 | 长整型字面量 |
| CONSTANT_Double_info | 6 | 双精度浮点型字面量 |
| CONSTANT_Class_info | 7 | 类或接口的符号引用 |
| CONSTANT_String_info | 8 | 字符串类型字面量 |
| CONSTANT_Fieldref_info | 9 | 字段的符号引用 |
| CONSTANT_Methodref_info | 10 | 类中方法的符号引用 |
| CONSTANT_InterfaceMethodref_info | 11 | 接口中方法的符号引用 |
| CONSTANT_NameAndType_info | 12 | 字段或方法的部分符号引用 |
| CONSTANT_MethodHandle_info | 15 | 表示方法句柄 |
| CONSTANT_MethodType_info | 16 | 表示方法类型 |
| CONSTANT_Dynamic_info | 17 | 表示一个动态计算常量 |
| CONSTANT_InvokeDynamic_info | 18 | 表示一个动态方法调用点 |
| CONSTANT_Module_info | 19 | 表示一个模块 |
| CONSTANT_Package_info | 20 | 表示一个模块开放或者导出的包 |
常量池中常量项的结构总表
| 常量 | 项目 | 类型 | 描述 |
| CONSTANT_Utf8_info | tag | 1bit | 值为1 |
| length | 2bit | UTF-8编码的字符串占用的字符数 | |
| bytes | 1bit | 长度为length的UTF-8编码的字符串 | |
| CONSTANT_Integer_info | tag | 1bit | 值为3 |
| bytes | 4bit | 按照高位在前存储的int值 | |
| CONSTANT_Float_info | tag | 1bit | 值为4 |
| bytes | 4bit | 按照高位在前存储的float值 | |
| CONSTANT_Long_info | tag | 1bit | 值为5 |
| bytes | 8bit | 按照高位在前存储的long值 | |
| CONSTANT_Double_info | tag | 1bit | 值为6 |
| bytes | 8bit | 按照高位在前存储的double值 | |
| CONSTANT_Class_info | tag | 1bit | 值为7 |
| index | 2bit | 指向全限定名常量项的索引 | |
| CONSTANT_String_info | tag | 1bit | 值为8 |
| index | 2bit | 指向字符串字面量的索引 | |
| CONSTANT_Fieldref_info | tag | 1bit | 值为9 |
| index | 2bit | 指向声明字段的类或者接口描述符CONSTANT_Class_info的索引项 | |
| index | 2bit | 指向字段描述符CONSTANT_NameAndType的索引项 | |
| CONSTANT_Methodref_info | tag | 1bit | 值为10 |
| index | 2bit | 指向声明方法的类描述符CONSTANT_Class_info的索引项 | |
| index | 2bit | 指向名称及类型描述符CONSTANT_NameAndType的索引项 | |
| CONSTANT_InterfaceMethodref_info | tag | 1bit | 值为11 |
| index | 2bit | 指向声明方法的接口描述符CONSTANT_Class_info的索引项 | |
| index | 2bit | 指向名称及类型描述符CONSTANT_NameAndType的索引项 | |
| CONSTANT_NameAndType_info | tag | 1bit | 值为12 |
| index | 2bit | 指向该字段或者方法名称常量项的索引 | |
| index | 2bit | 指向该字段或者方法描述符常量项的索引 | |
| CONSTANT_MethodHandle_info | tag | 1bit | 值为15 |
| reference_kind | 1bit | 值为1-9之间.它决定方法句柄的类型方法句柄类型的值,表示方法句柄的字节码行为 | |
| reference_kind | 2bit | 值必须是对常量池的有效索引 | |
| CONSTANT_MethodType_info | tag | 1bit | 值为16 |
| descriptor_index | 2bit | 值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示方法的描述符 | |
| CONSTANT_Dynamic_info | tag | 1bit | 值为16 |
| bootstrap_method_attr_index | 2bit | 值必须是对class文件引导方法表的bootstrap_method[]数组的有效索引 | |
| name_and_type_index | 2bit | 值必须是对常量池的有效索引,该项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符 | |
| CONSTANT_InvokeDynamic_info | tag | 1bit | 值为18 |
| bootstrap_method_attr_index | 2bit | 值必须是对class文件引导方法表的bootstrap_method[]数组的有效索引 | |
| name_and_type_index | 2bit | 值必须是对常量池的有效索引,该项必须是CONSTANT_NameAndType_info结构,表示方法名和方法描述符 | |
| CONSTANT_Module_info | tag | 1bit | 值为19 |
| name_index | 2bit | 值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示模块名称 | |
| CONSTANT_Package_info | tag | 1bit | 值为20 |
| name_index | 2bit | 值必须是对常量池的有效索引,该项必须是CONSTANT_Utf8_info结构,表示包名称 |
3) 访问标志(2字节):标识一些类或者接口层次的访问信息
| 标志名称 | 标志值 | 含义 |
| ACC_PUBLIC | 0x0001 | 是否为public类型 |
| ACC_FINAL | 0x0010 | 是否声明为final,只有类能设置 |
| ACC_SUPER | 0x0020 | 是否允许使用invokespecial字节码指令的新语义,JDK1.0.2后皆为true |
| ACC_INTERFACE | 0x0200 | 标识这是一个接口 |
| ACC_ABSTRACE | 0x0400 | 是否为abstract类型,接口或抽象类为true,其他为false |
| ACC_SYNTHETIC | 0x1000 | 标识这个类并非由用户代码产生 |
| ACC_ANNOTATION | 0x2000 | 标识这是一个注解 |
| ACC_ENUM | 0x4000 | 标识这是一个枚举 |
| ACC_MODULE | 0x8000 | 标识这是一个模块 |
4) 类索引、父类索引与接口索引集合(入口u2数据类型表示集合的容量计数):类索引用于确认这个类的全限定名;父类索引用于确认类的父类的全限定名(除了Object类,其他类的索引都不为0);接口索引集合按implements关键字或extends关键字后的接口顺序从左到右排列在集合里.
5) 字段表集合(入口u2数据类型表示集合的容量计数):用于描述接口或者类中声明的变量.
字段表结构:
| 类型 | 名称 | 数量 |
| 2bit | access_flags | 1 |
| 2bit | name_index | 1 |
| 2bit | descriptor_index | 1 |
| 2bit | attributes_count | 1 |
| attribute_info | attributes | attributes_count |
access_flags
| 标志名称 | 标志值 | 含义 |
| 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 | 0x4000 | 字段是否enum |
描述符是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值.常见描述符标志字符含义:
| 标识字符 | 含义 |
| B | 基本类型byte |
| C | 基本类型char |
| D | 基本类型double |
| F | 基本类型float |
| I | 基本类型int |
| J | 基本类型long |
| S | 基本类型short |
| Z | 基本类型boolean |
| V | 特殊类型void |
| L | 对象类型 |
对于数组类型,每个维度使用一个前置的" [ "字符描述;用描述符描述方法时,按照先参数列表、后返回值的顺序描述,参数列表按参数的顺序放在小括号()内.
6) 方法表集合:
方法表结构:
| 类型 | 名称 | 数量 |
| 2bit | access_flags | 1 |
| 2bit | name_index | 1 |
| 2bit | descriptor_index | 1 |
| 2bit | attributes_count | 1 |
| attribute_info | attributes | attributes_count |
access_flags:
| 标志名称 | 标志值 | 含义 |
| 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_VARARGS | 0x0080 | 方法是否接受不定参数 |
| ACC_NATIVE | 0x0100 | 方法是否为native |
| ACC_ABSTRACT | 0x0400 | 方法是否为abstract |
| ACC_STRICT | 0x0800 | 方法是否为strictfp |
| ACC_SYNTHETIC | 0x1000 | 方法是否为编译器自动产生 |
在Java语言中,要重载一个方法,处理要和原方法具有相同的名称外,还要有一个和原方法不同的特征签名.特征签名是指一个方法内各个参数在常量池中的字段符号引用的集合.返回值不在特征签名内,所以无法通过返回值不同进行重载.在class文件中,只要描述符不是完全一致的两个方法可以共存,即方法有相同的名称和特征签名,只要返回值不同,可以合法共存.
7) 属性表集合:
| 属性名称 | 使用位置 | 含义 |
| Code | 方法表 | Java代码编译成的字节码指令 |
| ConstantValue | 字段表 | 由final关键字定义的常量值 |
| Deprecated | 类,方法表,字段表 | 被声明为deprecated的方法和字段 |
| Exceptions | 方法表 | 方法抛出的异常列表 |
| EnclosingMethod | 类文件 | 仅当一个类为局部类或者匿名类才拥有,标示该类所在的外围方法 |
| InnerClasses | 类文件 | 内部类列表 |
| LineNumberTable | Code属性 | Java源码的行号和字节码指令的对应关系 |
| LocalVariableTable | Code属性 | 方法的局部变量描述 |
| StackMapTable | Code属性 | 供新的类型检查验证器检查和处理目标方法的局部变量和操作数栈所需类型是否匹配 |
| Signature | 类,方法表,字段表 | 用于支持泛型情况下的方法签名 |
| SourceFile | 类文件 | 记录源文件名称 |
| SourceDebugExtension | 类文件 | 用于存储额外的调试信息(例如JSP的调试) |
| Synthetic | 类,方法表,字段表 | 标识方法或字段为编译器产生 |
| LocalVariableTypeTable | 类 | 描述泛型参数化类型 |
| RuntimeVariableAnnoations | 类,方法表,字段表 | 用于指明哪些注解运行时可见 |
| RuntimeInvisibleAnnoations | 类,方法表,字段表 | 用于指明哪些注解运行时不可见 |
| RuntimeVisibleParameterAnnoations | 方法表 | 用于指明哪些方法参数的注解运行时可见 |
| RuntimeInvisibleParameterAnnoations | 方法表 | 用于指明哪些方法参数的注解运行时不可见 |
| AnnoationDefault | 方法表 | 记录注解类元素的默认值 |
| BoostrapMethods | 类文件 | 保存invokeDynamic指令引用的引导方法限定符 |
| RuntimeVisibleTypeAnnoations | 类,方法表,字段表,code属性 | 用于指明哪些类的注解运行时可见 |
| RuntimeInvisibleTypeAnnoations | 类,方法表,字段表,code属性 | 用于指明哪些类的注解运行时不可见 |
| MethodParameters | 方法表 | 用来支持将方法名称编译进class文件并运行时获取 |
| Module | 类 | 记录module的名称及相关信息(requires,exports,opens,uses,provides) |
| ModulePackages | 类 | 记录模块中所有被exports或opens的包 |
| ModuleMainClass | 类 | 用来指定模块的主类 |
| NestHost | 类 | 用于支持嵌套类的反射和访问控制的API,获取自己的宿主类 |
| NestMembers | 类 | 用于支持嵌套类的反射和访问控制的API,宿主类获取自己的内部类 |
属性表结构
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 1bit | info | attribute_length |
7.1) Code属性(接口或抽象类的方法可不存在)
| 类型 | 名称 | 数量 | 含义 |
| 2bit | attribute_name_index | 1 | 指向CONSTANT_Utf8_info型常量的索引,值固定为"Code" |
| 4bit | attribute_length | 1 | 属性值的长度 |
| 2bit | max_stack | 1 | 操作栈深度的最大值 |
| 2bit | max_local | 1 | 局部变量表所需的存储空间,单位是变量槽(JVM会对变量槽进行重用,因此数量并非所有局部变量和,同时this关键字在参数列表和方法体内会占用一个变量槽) |
| 4bit | code_length | 1 | 编译后生成的字节码指令的长度(虽然理论值有2^32,但是JVM限制方法不超过65525条字节码指令,超过会拒绝编译) |
| 1bit | code | code_length | 存储字节码指令的一系列字节流 |
| 2bit | exception_table_length | 1 | |
| exception_info | exception_table | exception_table_length | JVM通过异常表而不是通过跳转指令实现异常和finally处理机制 |
| 2bit | attributes_count | 1 | |
| attribute_info | attributes | attributes_count |
7.2) Exceptions属性结构
| 类型 | 名称 | 数量 | 含义 |
| 2bit | attribute_name_index | 1 | |
| 4bit | attribute_length | 1 | |
| 2bit | number_of_exceptions | 1 | 表示方法可能抛出number_of_exceptions种受检异常(除RuntimeException外的异常) |
| 2bit | exception_index_table | number_of_exceptions | 指向常量池中CONSTANT_Class_info型常量的索引 |
7.3) LineNumberTable属性结构(非运行必要,可通过-g:none或者-g:lines取消或生存此项信息,不生成的影响就是抛出异常不会显示出错的行号,debug时也无法按源码行设置断点):
| 类型 | 名称 | 数量 | 备注 |
| 2bit | attribute_name_index | 1 | |
| 4bit | attribute_length | 1 | |
| 2bit | line_number_table_length | 1 | |
| line_number_info | line_number_table | line_number_table_length | 包含start_pc(字节码行号)和line_number(源码行号)两个u2类型数据 |
7.4) LocalVariableTable属性结构(描述栈帧中局部变量表的变量和Java源码中定义的变量之间的关系,非运行必需,通过-g:none或者-g:vars取消或生成这项信息,取消的影响就是引用方法时,参数名称会丢失):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 2bit | local_variable_table_length | 1 |
| local_variable_info | local_variable_table | local_variable_table_length |
local_variable_info项目结构:
| 类型 | 名称 | 数量 | 含义 |
| 2bit | start_pc | 1 | 局部变量生命周期开始的字节码偏移量 |
| 2bit | length | 1 | 作用范围覆盖的长度 |
| 2bit | name_index | 1 | 指向常量池CONSTANT_Utf8_info型常量的索引,代表局部变量的名称 |
| 2bit | descriptor_index(LocalVariableTypeTable中此项为Signature) | 1 | 指向常量池CONSTANT_Utf8_info型常量的索引,代表局部变量的描述符(LocalVariableTypeTable此处用于描述泛型) |
| 2bit | index | 1 | 局部变量表中变量槽的位置 |
7.5) SourceFile属性结构(非运行必要,可通过-g:none或者-g:source取消或生存此项信息,不生成的影响就是抛出异常不会显示出错代码所属文件名)
| 类型 | 名称 | 数量 | 含义 |
| 2bit | attribute_name_index | 1 | |
| 4bit | attribute_length | 1 | |
| 2bit | sourcefile_index | 1 | 指向常量池CONSTANT_Utf8_info型常量的索引,常量值是源码文件的文件名 |
7.6) SourceDebugExtension属性结构(一个类最多允许一个SourceDebugExtension属性):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 1bit | debug_extension[attribute_length](变长UTF-8字符串) | 1 |
7.7) ConstantValue属性结构(JVM对非static类型的变量是在实例构造器<init>()方法中进行的;对于final和static修饰的变量如果数据类型是基本类型或者String,生成ConstantValue进行初始化,否则在<cinit>()方法中进行初始化):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 2bit | constantvalue_index | 1 |
7.8) InnerClasses属性结构(记录内部类和宿主类之间的关联):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 2bit | number_of_classes | 1 |
| inner_class_info | inner_classes | number_of_classes |
inner_class_info项目结构:
| 类型 | 名称 | 数量 | 含义 |
| 2bit | inner_class_info_index | 1 | 指向CONSTANT_Class_info型常量的索引,代表内部类的符号引用 |
| 2bit | outer_class_info_index | 1 | 指向CONSTANT_Class_info型常量的索引,代表宿主类的符号引用 |
| 2bit | inner_name_index | 1 | 指向CONSTANT_Utf8_info型常量的索引,代表这个内部类的名称,如果是匿名内部类,值为0 |
| 2bit | inner_class_access_flags | 1 | 内部类的访问标志 |
inner_class_access_flags
| 标志名称 | 标志值 | 含义 |
| ACC_PUBLIC | 0x0001 | 内部类是否为public |
| ACC_PRIVATE | 0x0002 | 内部类是否为private |
| ACC_PROTECTED | 0x0004 | 内部类是否为protected |
| ACC_STATIC | 0x0008 | 内部类是否为static |
| ACC_FINAL | 0x0010 | 内部类是否为final |
| ACC_INTERFACE | 0x0020 | 内部类是否为接口 |
| ACC_ABSTRACT | 0x0400 | 内部类是否为abstract |
| ACC_SYNTHETIC | 0x1000 | 内部类是否由用户代码产生 |
| ACC_ANNOTATION | 0x2000 | 内部类是否为一个注解 |
| ACC_ENUM | 0x4000 | 内部类是否为一个枚举 |
7.9) Deprecated属性结构(属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length(值必须为0x0000) | 1 |
7.10) Synthetic属性结构(属于标志类型的布尔属性,只存在有和没有的区别,没有属性值的概念,所有不属于用户代码产生的类、方法以及字段都应设置为Synthetic属性或者ACC_SYNTHETIC标志位的一项,除了实例构造器"<init>()"方法和类构造器"<cinit>()"方法):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length(值必须为0x0000) | 1 |
7.11) StackMapTable属性结构(包含零到多个栈映射帧,每个栈映射帧显示或隐式的代表一个字节码偏移量,用于表示执行到该字节码时局部变量表和操作数栈的验证类型.类型检查验证器会通过检查目标方法的局部变量和操作数栈所需的类型确认一段字节码指令是否符合逻辑约束.一个方法的Code属性最多只能有一个StackMapTable属性):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 2bit | number_of_entries | 1 |
| stack_map_frame | stack_map_frame_entries | number_of_entries |
7.12) Signature属性结构(用于存储类、接口、初始化方法或成员的泛型签名包含的类型变量和参数化类型的泛型签名信息):
| 类型 | 名称 | 数量 | 含义 |
| 2bit | attribute_name_index | 1 | |
| 4bit | attribute_length | 1 | |
| 2bit | signature_index | 1 | 必须指向常量池CONSTANT_Utf8_info类型的有效索引,表示类签名或者方法类型签名或字段类型签名 |
7.13) BootstrapMethod属性结构(用于保存invokeDynamic指令引用的引导方法限定符,类文件的属性表中最多只能有一个BootstrapMethod属性,实现意义:lambda表达式和接口默认方法的实现):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 2bit | num_boostrap_methods | 1 |
| bootstrap_method | bootstrap_methods | num_boostrap_methods |
bootstrap_method项目结构:
| 类型 | 名称 | 数量 | 含义 |
| 2bit | boostrap_method_ref | 1 | 指向常量池CONSTANT_MethodHandle_info结构的有效索引 |
| 2bit | num_bootstrap_arguments | 1 | 成员的数量 |
| 2bit | boostrap_arguments | num_bootstrap_arguments | 必须是CONSTANT_xx_info结构的有效索引 |
7.14) MethodParameters属性结构(用于程序反射时能获取方法参数名称):
| 类型 | 名称 | 数量 |
| 2bit | attribute_name_index | 1 |
| 4bit | attribute_length | 1 |
| 1bit | parameters_count | 1 |
| parameter | parameters | parameters_count |
parameter项目结构:
| 类型 | 名称 | 数量 | 含义 |
| 2bit | name_index | 1 | 指向常量池CONSTANT_Utf8_info结构的有效索引 |
| 2bit | access_flags | 1 | 0x0010(ACC_FINAL):表示参数被final修饰; 0x1000(ACC_SYNTHETIC):表示参数是编译器自动生成的; 0x8000(ACC_MANDATED):表示参数是源文件中隐式定义的,比如this关键字 |




