JVM 类文件结构
本文将介绍类文件的结构。
一、什么是类文件?
类文件,即 Class 文件。
类文件由编译器根据代码编译而成。
类文件可以由 JVM 载入并执行。
类文件与平台无关,其内容只针对通用的执行平台——JVM。类文件和 JVM 一起,实现了 Java 的 “一次编写,处处运行”。
二、类文件结构
1. 整体说明
(1) 二进制流
以字节为基础单位的二进制流。
(2) 紧凑排列
各个数据项目严格按照顺序紧凑排列,中间没有任何分隔符。
(3) 数据类型
包含两种数据类型,如下:
- 无符号数:可以用于描述数字、索引引用、数量值、字符串值;以 u1、u2、u4、u8 分别代表使用不同数量字节的无符号数
- 表:由多个无符号数、表构成的复合数据结构,简单来说,一个表由多个元素紧密排列构成,这些数据项可以是无符号数、表;Class 文件本身就可以看作是一个表;表的命名习惯以
_info
结尾
2. 魔数
每个 Class 文件的头 4 个字节被称为魔数,其值固定为 0xCAFEBABE
(咖啡宝贝)。
JVM 会读取魔数以确认文件符合要求。
3. 版本号
紧随魔数的 4 个字节存储的是 Class 文件的版本号,其中前两个字节存储次版本,后两个字节存储主版本。
JVM 会读取版本号,并拒绝执行版本超过自身的 Class 文件。
4. 常量池
常量池可以比喻为 Class 文件里的资源仓库。
常量池中常量的数量是不固定,因此在常量池开始的地方会放置一个 u2 类型的数据,其值为常量数。
每一个常量具体在 Class 文件中都是一个表,表的类型共有 17 种,如下:
这些常量可以被分为两大类:
- 字面量:常量,例如字符串、final 常量等
- 符号引用:类、接口、字段、方法的符号引用;在类加载或运行时,由 JVM 将符号引用解析为直接引用
5. 访问标志
访问标志由 2 个字节构成,共有 2 x 8 = 16
个标志位。
目前共定义了 9 个标志位,如下:
6. 类索引、父类索引、接口索引集合
其中,
- 类索引:由一个索引项构成
- 父类索引:由一个索引项构成
- 接口索引集合:由多个索引项构成
索引项是一个 u2 类型的数据,指向常量池中一个类型为 CONSTANT_Class_info 的常量。
通过索引项,可以获取到类、父类、实现接口的全限定名。
7. 字段表集合
字段表用于描述类中声明的 field。
字段表结构如下:
- access_flags:即访问标志;与类的访问标志类似
- name_index:对常量池项的引用;表示字段的简单名称
- descriptor_index:对常量池项的引用;表示字段的描述符,即参数类型
- attributes_count 和 arrtibutes:属性表集合;用于存储一些额外信息
8. 方法表集合
方法表用于描述类中声明的 method。
方法表结构如下:
access_flags:即访问标志;与类的访问标志类似
name_index:对常量池项的引用;表示方法的简单名称
descriptor_index:对常量池项的引用;表示方法的描述符,即返回类型、参数列表
attributes_count 和 arrtibutes:属性表集合;用于存储一些额外信息
属性表集合中的 Code 属性存放着(编译成字节码指令的)方法具体代码
三、字节码指令
1. 概述
字节码指令由两部分组成:
- 第一部分:操作码;一个字节长度,代表某种特定操作含义的数字
- 第二部分:操作数集合;操作所需参数,有零至多个
2. 操作
由于操作码仅由一个字节存放,因此操作数量不能操作 256 条。
与数据类型相关的操作如图所示:
另外还有与数据类型无关的操作若干,包括对象创建及访问、操作数栈管理、控制转移、方法调用和返回、异常处理、同步等。
参考
- 深入理解 Java 虚拟机