前言
为什么要学习Java字节码呢,因为我们学的是插桩字节码技术,这块技术的根底就是字节码,要学会字节码的阅读和字节码的编写,虽然现在很多工具可以帮我们阅读和编写,但最根本的知识还是要理解的。万层楼高从地起,打好基础是关键。
字节码和ClassFile关系
ClassFile是以.class
结尾的二进制文件,而该二进制文件中存储的内容就是16进制的Java字节码,在我们学习的插桩技术中,本质就是修改Java字节码文件,也就是要修改ClassFile,读懂Java字节码的基础就是要读懂ClassFile的意思
ClassFile解读
ClassFile是字节码存储文件,规定了规范,我们只需要按照规范的内容进行解析和解读即可知道表达的意思,我们通过简单的例子来演示
1、Hello Word
简单的写一段HelloWord代码,
package hensen;
public class Demo {
public static void main(String[] args) {
System.out.println("Hello World.");
}
}
通过javac生成class文件,通过Editor010读取里面的十六进制格式的内容
通过javap -v 查看class
文件的结构,这个接口是java帮我们打印出来的,下面我们就看看怎么解析的
2、ClassFile结构解析
Class文件的格式,解析出来的结构如下
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];
}
- u1: 表示占用1个字节,2个16进制字符
- u2: 表示占用2个字节,4个16进制字符
- u4: 表示占用4个字节,8个16进制字符
- u8: 表示占用8个字节,16个16进制字符
3、字节码解析案例
(一)魔数
CAFE BABE
第1 - 4个字节表示magic
魔数,魔数的作用是Class文件的标识,虚拟机会判断这个文件是否为一个能被虚拟机接受的Class文件
(二)文件版本
0000 0034
- 第5 - 6个字节表示
minor_version
JDK的次版本号 - 第7 - 8个字节表示
major_version
JDK的主版本号
JDK版本 | 次版本号 | 主版本号 | 十进制 |
---|---|---|---|
JDK1.7 | 0000 | 0033 | 51 |
JDK1.8 | 0000 | 0034 | 52 |
(三)常量池
接着是到了常量池的解析
001D
- 前2个字节表示常量池个数,其值为29,表示一共有29 - 1 = 28个常量
- 后N个字节表示常量池的具体内容
确定常量池数量后,要确定常量池内容
cp_info {
u1 tag;
u1 info[];
}
常量池的内容都会有个统一个格式,前1个字节表示类型,后面的字节表示常量池的值
0A 00 06 00 0F
字段 | 长度 | 字段值 | 说明 |
---|---|---|---|
CONSTANT_Methodref_info | u1 | tag(0x0A) | 类中方法的符号引用 |
— | u2 | class_index | 指向声明方法的类描述符CONSTANT_Class_info的索引项 |
— | u2 | name_and_type_index | 指向名称及类型描述符CONSTANT_NameAndType的索引项 |
通过常量池寻表,可以发现,该常量项第2-3个字节表示类信息,第4-5个字节表示名称及类描述符
- class_index:0x06(#6)
- name_and_type_index:0x0F(#15)