0%

字节码文件

字节码文件

字节码文件中包含的内容有包含类的版本信息、字段、方法以及接口等描述信息外,还有常量池表(Constant Pool Table),包括各种字面量和对类型、域(Field)和方法的符号引用,指令代码行号表等信息

  • java栈中:局部变量表、操作数栈
  • java堆中
  • 常量池
  • 帧数据区、方法区的剩余情况

文件结构

u1、u2、u4、u8分别表示1个字节、2个字节、4个字节、8个字节的无符号数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ClassFile {
u4 magic;// 魔数,识别class文件格式 cafe babe
u2 minor_version; // 副版本号
u2 major_version; // 主版本号
u2 constant_pool_count; //常量池计数器,计数从1开始,记录常量池表中的数量,减一等于常量池表的长度
cp_info constant_pool[constant_pool_count-1]; //常量池表,用于存放编译时期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放
u2 access_flags; // 访问标识
u2 this_class; // 类索引,对应constant_pool表中的一个有效索引值
u2 super_class; // 父类索引,必须是0或者对应constant_pool表中的一个有效索引值
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]; //属性表
}

魔数

class文件的第1-4个字节表示该文件的魔数,魔数是用来识别class文件格式,java的class文件中都是 0xCAFEBABE

副版本号

class文件的第5-6个字节表示该class文件的副版本号,即编译该class文件的JDK副版本号

主版本号

class文件的第7-8个字节表示该class文件的主版本号,即编译该class文件的JDK主版本号

常量池

常量池分为常量池计数器和常量池表

常量池计数器

由于常量池列表中的常量数并不固定,所以需要一个常量池计数器来统计常量池中常量项的数量,计数从1开始,记录常量池表中的数量,减一等于常量池表的长度

常量池表

常量池表中主要存放字面量符号引用,这部分内容将在类加载后进入方法区的运行时常量池中存放

字面量主要是文本字符串声明为final的常量值

1
2
3
4
cp_info {
u1 tag;
u1 info[];
}

tag项说明

常量类型 标志值 描述 结构
CONSTANT_Class 7 类或接口的符号引用 {
u1 tag;
u2 name_index;
}
CONSTANT_Fieldref 9 字段的符号引用 {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_Methodref 10 类中方法的符号引用 {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_InterfaceMethodref 11 接口中方法的符号引用 {
u1 tag;
u2 class_index;
u2 name_and_type_index;
}
CONSTANT_String 8 字符串类型字面量 {
u1 tag;
u2 string_index;
}
CONSTANT_Integer 3 整型字面量 {
u1 tag;
u4 bytes;
}
CONSTANT_Float 4 浮点型字面量 {
u1 tag;
u4 bytes;
}
CONSTANT_Long 5 长整型字面量 {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_Double 6 双精度浮点型字面量 {
u1 tag;
u4 high_bytes;
u4 low_bytes;
}
CONSTANT_NameAndType 12 字段或方法的符号引用 {
u1 tag;
u2 name_index;
u2 descriptor_index;
}
CONSTANT_Utf8 1 UTF-8编码的字符串 {
u1 tag;
u2 length;
u1 bytes[length];
}
CONSTANT_MethodHandle 15 方法句柄 {
u1 tag;
u1 reference_kind;
u2 reference_index;
}
CONSTANT_MethodType 16 标志方法类型 {
u1 tag;
u2 descriptor_index;
}
CONSTANT_InvokeDynamic 18 动态方法调用点 {
u1 tag;
u2 bootstrap_method_attr_index;
u2 name_and_type_index;
}

符号引用主要是类和接口的全限定名,字段的名称和描述符,方法的名称和描述符

当虚拟机做类加载时,将会从常量池获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址中

字段描述符
FieldType term Type
B byte
C char
D double
F float
I int
J long
L ClassName ; 对象reference`
S short
Z boolean
[ 数组reference

访问标识

类访问标识

标识名称 含义
ACC_PUBLIC 0x0001 标识为public,可以被包外访问
ACC_FINAL 0x0010 标识被声明为final,不允许有子类
ACC_SUPER 0x0020 表示允许使用invokespecial字节码指令来调用父类的方法
ACC_INTERFACE 0x0200 标识这是一个接口
ACC_ABSTRACT 0x0400 声明为abstract,不能直接被实例化
ACC_SYNTHETIC 0x1000 表示是由编译器产生的类,没有对应的源码
ACC_ANNOTATION 0x2000 声明为annotation类型,注解
ACC_ENUM 0x4000 声明为enum类型,枚举

字段访问标识

标识名称 含义
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类型,枚举

方法访问标识

标识名称 含义
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 bridge,方法由编译器产生
ACC_VARARGS 0x0080 方法带有变长参数
ACC_NATIVE 0x0100 native,标识本地方法
ACC_ABSTRACT 0x0400 声明为abstract,没有具体实现
ACC_STRICT 0x0800 strictfp,方法使用FP-strict浮点格式
ACC_SYNTHETIC 0x1000 表示是由编译器产生的类,没有对应的源码

索引信息

访问标识之后则是索引信息,有类索引、父类索引、接口索引,通过这三项数据来确定这个类的继承关系

类索引

用于确定这个类的全限定名,指向常量池中的常量

父类索引

用于确定这个类的父类的全限定名,指向常量池中的常量

接口索引

描述哪个类实现了哪些接口,按照implements的顺序从左到右排列在接口索引集合中,通过interfaces_count记录数量

字段表集合

1
2
3
4
5
6
7
field_info{
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

字段计数器和字段表

字段包括类变量以及实例变量,不包括方法内部、代码块内部声明的局部变量,也不会列出从父类或者实现的接口中继承来的字段

字段的名称、类型是引用的常量池中的常量来进行描述的,常量池中描述了每个字段的完整信息,包括字段标识符、访问修饰符、static修饰、final修饰等

方法表集合

1
2
3
4
5
6
7
method_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}

方法表中存储的是一个一个的method_info,method_info结构可以表示类和接口中定义的所有方法,包括实例方法、类方法、实例初始化方法和类或接口初始化方法

属性表集合

1
2
3
4
5
attribute_info {
u2 attribute_name_index;
u4 attribute_length;
u1 info[attribute_length];
}

记录的是class文件所携带的辅助信息,如class文件的源文件名称,以及带有RetentionPolicy.CLASS或RetentionPolicy.RUNTIME的注解

欢迎关注我的其它发布渠道