16进制文件 下列的数字代表字节数 索引中存放的是常量池中第几个常量的引用(常量池计数器从1开始 1代表存在0个常量)
class文件中方法的返回值也作为特征签名即可同时存在一个class文件中 重载
特征签名 (class)返回值 方法名 参数列表
特征签名 (类) 方法名 参数列表
字段表结构【2(访问权限标记符)+2(名字索引)+2(描述标识字符)+2(属性计数器)+ attribute_info(属性)】
attribute_info(属性) 基本结构 其它按需增加
2(属性名attribute_name_index)+4(长度attribute_length)+1(信息info)
描述标识字符B byte C char D double F float I int J long S short Z boolean V void L 对象类型 如Ljava/lang/Object int indexOf(char[] s,int a,int b,char[] ss,int x,int y,int z)描述符为([CIICIII)I
(访问权限标记符)
ACC_PUBLIC 0X0001 ACC_PRIVATE 0X0002 ACC_PROTECT 0X0004 ACC_STATIC 0X0008
ACC_FINAL 0X0010 ACC_VOLATILE 0X0040 ACC_TRANSIENT 0X0080
ACC_SYNTHETIC 0X1000 ACC_ENUM 0X4000
方法表结构【2(访问权限标记符)+2(名字索引)+2(描述标识字符)+2(属性计数器)+attribute_info(属性)】
ACC_PUBLIC 0X0001 ACC_PRIVATE 0X0002 ACC_PROTECT 0X0004 ACC_STATIC 0X0008
ACC_FINAL 0X0010 ACC_SYNCHRONIZED 0x0020 ACC_BRIGGE 0X0040 是否由编译器产生的桥接方法 ACC_VARARGS 0X0080 接受不定参
ACC_NATIVE 0x0100 ACC_ABSTRACT 0x0400 ACC_STRICTFP 0x0800 是否为strictfp
ACC_SYNTHETIC 0X1000
类的访问权限标志
ACC_PUBLIC 0X0001 是否public
ACC_FINAL 0x0010 ACC_SUPER 0X0020 jdk以后1.0默认真
ACC_INTERFACE 0X0200 ACC_ABSTRACT 0X0400
ACC_SYNTHETIC 0X1000标识类并非由用户代码产生 ACC_ANNOTATION 0X2000标识为注解 ACC_ENUM 0X4000
常量池
4(魔数cafebaby)+4(版本号 2次+2主)+【2(常量池常量个数)+一系列表(14种,见下图)】+2(类的访问权限标志)+2(类索
接口集合 字段表集合
引)+2(父类索引)+【2(接口计数器)+一系列接口索引()】 +【2(字段计数器,标记字段个数)+一系列字段表结构】+
方法表集合(方法的java代码存放在Code属性里面)
【2(方法计数器)+一系列方法】 +【2 attribute_count+attribute_info】
Attribute_info
1.Code属性 方法参数值从1开始
显式异常处理表【2 (start_pc)+2(end_pa)+2(handler_pc)+2(catch_type)】
字节码在spc行到epc行出现了catch_type(指向一个class_info型常量索引)或者其它子类的异常,则转到h_pc继续执行,当c_t为0时,代表任意异常情况都需要转向h_pc进行处理.
2.Exception属性
与code平级 作用是列举方法中可能抛出的受查异常 throws关键字后的列举的异常
number_of_exception exception_index_table
2(属性名)+4(属性长)+2(可能抛出多少种异常,即多少个异常表)+2(一个异常表,包含一个class_info索引,异常类型)...
3.LineNumberTable属性
用于描述java源码行号与字节码行号之间的对应关系 非必须,异常时 是否显示堆栈出错行号 默认开
2(name)+4(length)+2(line_number_table_length)+line_number_table(数量为line_number_table_length,类型为line_number_info的集合)
line_number_info 包括 2(start_pc 字节码行号)+2(line_number java源代码行号)
4.LocalVariableTable属性
描述栈帧中局部变量表中的变量与java源代码中定义的变量之间的关系 非必须 关闭以后其他人引用该方法的时候,所有的参数名称丢失,ide会用arg0,arg1.....参数代替而且调试期间无法根据参数名称从上下文获得参数值
2(name)+4(count)+2(local_variable__table_length)+local_variable_info(数量为local_variable__table_length,类型为local_variable__info的集合)
局部变量生命周期开始的字节码偏移量以及作用范围覆盖的长度
local_variable__info 包括 2(start_pc)+2(length)+2(name_index)+2(decription_index)+2(index)
局部变量名+描述符 栈帧局部变量表中Slot的位置
当为double long时 占用index index+1
5.SourceFile属性.
用于记录生成这个Class文件的源文件名称,可选非必须
2(attribute_name_index)+4(attribute_length)+2(sourcefile_index指向常量池中CONSTANT_info型常量的索引,即文件名)
6. ConstantValue属性
通知虚拟机自动为静态变量赋值,只有被static关键字修饰的变量才可以拥有该属性
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
魔数,魔数的唯一作用是确定这个文件是否为一个能被虚拟机所接受的 Class 文件。魔
数值固定为 0xCAFEBABE,不会改变
minor_version、major_version
副版本号和主版本号
constant_pool_count
常量池计数器,constant_pool_count的值等于constant_pool表中的成员数加1。
constant_pool 表的索引值只有在大于 0 且小于 constant_pool_count 时才会被
认为是有效的,对于 long 和 double 类型有例外情况,可参见§4.4.5。
constant_pool[]
常量池,constant_pool 是一种表结构(§4.4),它包含 Class 文件结构及其子结构
中引用的所有字符串常量、类或接口名、字段名和其它常量。常量池中的每一项都具备相
同的格式特征——第一个字节作为类型标记用于识别该项是哪种类型的常量,称为“tag
byte”。常量池的索引范围是 1 至 constant_pool_count−1
access_flags
访问标志,access_flags 是一种掩码标志,用于表示某个类或者接口的访问权限及基
础属性
ACC_PUBLIC 0x0001 可以被包的类外访问。
ACC_FINAL 0x0010 不允许有子类。
ACC_SUPER 0x0020
当用到 invokespecial 指令时,需要特殊处理 ③ 的
父类方法。
ACC_INTERFACE 0x0200 标识定义的是接口而不是类。
ACC_ABSTRACT 0x0400 不能被实例化。
ACC_SYNTHETIC 0x1000 标识并非 Java 源码生成的代码
ACC_ANNOTATION 0x2000 标识注解类型
ACC_ENUM 0x4000 标识枚举类型
带有 ACC_SYNTHETIC 标志的类,意味着它是由编译器自己产生的而不是由程序员
编写的源代码生成的。
带有 ACC_ENUM 标志的类,意味着它或它的父类被声明为枚举类型。
带有 ACC_INTERFACE 标志的类,意味着它是接口而不是类,反之是类而不是接口。
如果一个 Class 文件被设置了 ACC_INTERFACE 标志,那么同时也得设置ACC_ABSTRACT 标志
。同时它不能再设置 ACC_FINAL、ACC_SUPER 和 ACC_ENUM 标志。
注解类型必定带有 ACC_ANNOTATION 标记,如果设置了 ANNOTATION 标记ACC_INTERFACE
也必须被同时设置 如果没有同时设置 ACC_INTERFACE 标记,那么这个Class文件可以具有表
中的除ACC_ANNOTATION外的所有其它标记。当然 ACC_FINAL 和 ACC_ABSTRACT 这类互斥的标记除外
ACC_SUPER 标志用于确定该 Class 文件里面的 invokespecial 指令使用的是哪一种执行语义
目前 Java 虚拟机的编译器都应当设置这个标志。ACC_SUPER 标记是为了向后兼容旧编译器编译的
Class 文件而存在的
access_flags 标志位是为未来扩充而预留的,编译器中会被设置为 0, Java 虚拟机实现也会
自动忽略它们
this_class
类索引,this_class 的值必须是对 constant_pool 表中项目的一个有效索引值。
constant_pool 表在这个索引处的项必须为 CONSTANT_Class_info 类型常量
,表示这个 Class 文件所定义的类或接口
super_class
父类索引,对于类来说,super_class 的值必须为 0 或者是对 constant_pool 表中
项目的一个有效索引值。如果它的值不为 0,那 constant_pool 表在这个索引处的项
必须为 CONSTANT_Class_info 类型常量(§4.4.1),表示这个 Class 文件所定义的
类的直接父类。当前类的直接父类,以及它所有间接父类的 access_flag 中都不能带
有 ACC_FINAL 标记。对于接口来说,它的 Class 文件的 super_class 项的值必须是
对 constant_pool 表中项目的一个有效索引值。constant_pool 表在这个索引处的
项必须为代表 java.lang.Object 的 CONSTANT_Class_info 类型常量。
如果 Class 文件的 super_class 的值为 0,那这个 Class 文件只可能是定义的是
java.lang.Object 类,只有它是唯一没有父类的类。
interfaces_count
接口计数器
interfaces[]
接口表,interfaces[]数组中的每个成员的值必须是一个对 constant_pool 表中项
目的一个有效索引值,它的长度为 interfaces_count。每个成员 interfaces[i] 必
须为 CONSTANT_Class_info 类型常量(§4.4.1),其中 0 ≤ i <
interfaces_count。在 interfaces[]数组中,成员所表示的接口顺序和对应的源
代码中给定的接口顺序(从左至右)一样,即 interfaces[0]对应的是源代码中最左
边的接口
fields_count
字段计数器,fields_count 的值表示当前 Class 文件 fields[]数组的成员个数。
fields[]数组中每一项都是一个 field_info 结构的数据项,它用于表示
该类或接口声明的类字段或者实例字段
fields[]
字段表,fields[]数组中的每个成员都必须是一个 fields_info 结构(§4.5)的数
据项,用于表示当前类或接口中某个字段的完整描述。fields[]数组描述当前类或接口
声明的所有字段,但不包括从父类或父接口继承的部分
methods_count
方法计数器,methods_count 的值表示当前 Class 文件 methods[]数组的成员个数。
Methods[]数组中每一项都是一个 method_info 结构
methods[]
方法表,methods[]数组中的每个成员都必须是一个 method_info 结构的
数据项,用于表示当前类或接口中某个方法的完整描述。如果某个 method_info 结构
的 access_flags 项既没有设置 ACC_NATIVE 标志也没有设置 ACC_ABSTRACT 标志,
那么它所对应的方法体就应当可以被 Java 虚拟机直接从当前类加载,而不需要引用其它
类。method_info 结构可以表示类和接口中定义的所有方法,包括实例方法、类方法、
实例初始化方法方法 和类或接口初始化方法方法。methods[]数组
只描述当前类或接口中声明的方法,不包括从父类或父接口继承的方法
attributes_count
属性计数器,attributes_count 的值表示当前 Class 文件 attributes 表的成员个
数。attributes 表中每一项都是一个 attribute_info 结构 的数据项
attributes[]
属性表,attributes 表的每个项的值必须是 attribute_info 结构(§4.7)。在本
规范里,Class 文件结构中的 attributes 表的项包括下列定义的属性:
InnerClasses 、EnclosingMethod 、Synthetic 、
Signature 、SourceFile ,SourceDebugExtension
、Deprecated 、RuntimeVisibleAnnotations
、RuntimeInvisibleAnnotations 以及
BootstrapMethods 属性。对于支持 Class 文件格式版本号为 49.0 或
更高的 Java 虚拟机实现,必须正确识别并读取 attributes 表中的 Signature
、RuntimeVisibleAnnotations 和
RuntimeInvisibleAnnotations 属性。对于支持 Class 文件格式版
本号为 51.0 或更高的 Java 虚拟机实现,必须正确识别并读取 attributes 表中的
BootstrapMethods 属性。本规范要求任一 Java 虚拟机实现可以自动
忽略 Class 文件的 attributes 表中的若干(甚至全部)它不可识别的属性项。任何本
规范未定义的属性不能影响 Class 文件的语义,只能提供附加的描述信息 。