当你觉得达到了一定的技术瓶颈后,一定要抽空看看字节码,你会大有所获。 本节简单描述字节码文件的组成结构,旨在让大家对字节码有个大概的印象。
字节码是什么?
字节码是Java文件编译后生成的class文件。关于字节码,本人一直以来对其不太重视,有时候一看就眼困,但到了真正发自内心想要去了解去学,怀着好奇的心态去看书看规范,随着慢慢揭开字节码的面纱,才突然焕然大悟,大喊妙哉妙哉!!!
class文件结构
class文件结构按照固定顺序存储数据,数据的大小一般按1、2、4个字节区分,通常使用u1、u2、u4表示。存储的数据顺序为魔术、次版本号、主版本号、常量池计数器、常量池、访问标志、本类索引、父类索引、接口计数器、接口表、字段计数器、字段表、方法计数器、方法表、属性计数器、属性表。
class ClassFile {
//魔数
var magic: U4? = null
//次版本号
var minor_version: U2? = null
//主版本号 52-java8
var major_ersion: U2? = null
//常量池计数器
var constant_pool_count: U2? = null
//常量池表
var constant_pool: Array<CpInfo>? = null
//访问标志
var access_flags: U2? = null
//类索引
var this_class: U2? = null
//父类索引
var super_class: U2? = null
//接口计数器
var interfaces_count: U2? = null
//接口表
var interfaces: Array<U2>? = null
//字段计数器
var fields_count: U2? = null
//字段表
var fields: Array<field_info>? = null
//方法计数器
var methods_count: U2? = null
//方法表
var methods: Array<method_info>? = null
//属性计数器
var attributes_count: U2? = null
//属性表
var attributes: Array<attribute_info>? = null
}
-
魔数 u4
一般文件都有自己的魔数,程序判断文件类型不是通过扩展名来判断,因为拓展名可以随意修改,而是通过魔数来确认文件类型,class文件的魔数是前四位字节表示的0xCAFEBABE(咖啡宝贝),这个魔数也是Java语言的创始人想到自己在爪哇岛喝过一种美味的咖啡而得来的灵感。
-
主次版本号 u4
接下来四个字节表示主次版本号,前两个字节表示次版本号,后两字节表示主版本号,Java虚拟机实现规定本虚拟机所能支持的版本范围。
-
常量池计数器 u2
接下来两个字节表示常量池计数器,常量池计数器减一等于常量池大小。 常量池的每一项都有相同的特征,第一个字节作为类型标志,tag,用于确定是哪种常量格式。
-
常量池
常量池是表结构,常量池存储字符串常量、类名、接口名、字段名、方法名等其它常量。
-
访问标志 u2
访问标志用于表示类或接口的访问权限及属性。
| 标志名 | 值 | 含义 |
|---|---|---|
| ACC_PUBLIC | 0x0001 | 声明为public,包外可访问 |
| ACC_FINAL | 0x0010 | 声明final,不可被继承 |
| ACC_SUPER | 0x0020 | 当使用invokespecial指令时,需要对父类方法做特殊处理 |
| ACC_INTERFACE | 0x0200 | 定义为接口 |
| ACC_ABSTRACT | 0x0400 | 定义为抽象类,不可被实例化 |
| ACC_SYNTHETIC | 0x1000 | 声明synthetic,表示class文件不是Java源码生成 |
| ACC_ANNOTATION | 0x2000 | 注解类型 |
| ACC_ENUM | 0x4000 | 枚举类型 |
-
this_class u2
类索引,是常量池中有效的索引,并且常量类型为CONSTANT_Class_info。表示这个class文件定义的类或接口。
-
super_class u2
父类索引,为0或常量池中有效的索引,同上结构。表示这个类继承的直接父类。如果为0,则这个class文件只能表示Object,因为Object是唯一没有父类的类。
-
接口计数器 u2
表示该类或接口实现的直接接口数量,两个字节表示。
-
接口表
接口表存储该类实现的接口在常量池中的索引,常量类型为CONSTANT_Class_info,表内容顺序按源代码中从左到右的顺序存放,interfaces[0]是最左边实现的接口。
-
字段计数器 u2
表示该类拥有的字段数量,也是两个字节表示。
-
字段表
字段表存储该类各项字段信息,结构为fields_info。
-
方法计数器 u2
表示该类或接口中定义的所有方法数量,方法包括实例初始化方法、类方法、实例方法、类或接口初始化方法。
-
方法表
存储的每一项都是methods_info结构,如果该结构的access_flags标志没有设为ACCESS_ABSTRACT或ACCESS_NATIVE,则该结构中应包含方法实现所用的虚拟机指令。
-
属性计数器 u2
表示该class文件属性表的成员个数。
-
属性数组
表中每一项的结构都是attribute_info类型。
下一节会讲解各个结构详细存储的内容。