大纲
- 为什么会有字节码文件
- 生成字节码的编译器是什么
- 字节码文件的结构
- 字节码文件分析实战
1. 为什么会有字节码文件?
这就说到JVM的跨语言平台的特性了, 通过字节码, 任何实现了编译为字节码文件的编程语言都可以在JVM上运行
2. 生成字节码的编译器是什么?
JDK 生成字节码的编译器是 javac
(不同的代码编辑软件也会有不同,如eclipse 用的是EJC, IDEA默认用的javac
-
首先我们要明确一点生成字节码的编译器和运行字节码的编译器是不同的
-
学过编译原理的我们都清楚
编译分为前端和后端
, 而生成字节码的编译器就属于前端编译的工作 (语法,语义分析生成中间代码等等 -
而后端编译, 就是我们熟悉的JIT(Just In Time) 即时编译器, 以及解释器, 因为HotSpot 默认是mixed mode 即 解释和编译混合执行的, JIT 负责找到热点代码然后动态编译
3. 字节码文件的结构
常见结构包括[ 一般信息, 常量池, 接口, 字段, 方法, 属性 ]
注意 : 上图只是从jclasslib这个工具的角度描述的
(其实以上信息实际上字节码文件是严格按照一定顺序排列的,并且是以16进制的形式存储的,我们关注的重点不在于如何翻译)
需要重点了解的一些结构以及问题
- 常量池中的符号引用和直接引用
- 方法中的字节码指令
- 字段和属性的区别
常量池中的符号引用和直接引用
字面量 : CONSTANT_Utf8_info ( 文本字符串
符号 : CONSTANT_{*}_info ( 具有意义的描述符
符号引用 : 对应符号在常量池的索引
直接引用 : 对应内存中的地址
方法中的字节码指令
这就要提到方法栈中栈帧的两个重要结构了 [ 操作数栈, 局部变量表 ]
常见指令(大致形式,想要完整确切的去oracle官网查
- push : 压入操作数栈
- const : 将常量压入操作数栈
- store : 存入局部变量表
- load : 从局部变量表取出放入操作数栈中
- invokevirtual 可以被重写的方法
- invokespecial 一般用于调用<init>方法
- invokestatic 一般用于调用静态方法
- invokeinterface 一般用于调用接口
字段和属性的区别
字段 其实是成员变量
属性 是描述这个类的具体信息的