Java 程序是运行在 Java 虚拟机(JVM)上的, JVM 屏蔽了各个操作系统之间的差异, 使得 Java 代码只需要写一遍, 就可以在多个操作系统上运行。
Java源代码经过编译后会生成class文件, 我们首先来看一下class文件的结构。
class文件整体结构
类型 | 名称 | 说明 |
---|---|---|
u4 | magic | 魔数 |
u2 | minor_version | 副版本号 |
u2 | major_version | 主版本号 |
u2 | constant_pool_count | 常量池中常量的个数 |
cp_info | constant_pool | 常量池 |
u2 | access_flags | 访问标志 |
u2 | this_class | 类索引 |
u2 | super_class | 父类索引 |
u2 | interfaces_count | 接口个数 |
u2 | interfaces | 接口索引集合 |
u2 | fields_count | 字段个数 |
field_info | fields | 字段集合 |
u2 | methods_count | 方法个数 |
method_info | methods | 方法集合 |
u2 | attributes_count | 附加属性个数 |
attribute_info | attributes | 附加属性集合 |
class 文件中定义了两种数据类型:
- u1、u2、u4、u8 分别代表 1 个字节、2 个字节、4 个字节和 8 个字节的无符号数
- 以 _info 结尾的类型称为表。表是由多个无符号数或者其他表构成的复合类型, 整个 class 文件也可以视作是一张表
动手编译一个java文件
创建一个名为ClassFileDemo.java的文件, 输入下面内容:
public class ClassFileDemo {
int num;
public int getNum() {
return this.num;
}
}
打开命令行, 使用javac编译:
javac ClassFileDemo.java
在同一目录下会生成一个ClassFileDemo.class文件, 由于class文件不是文本文件, 无法用文本编辑器直接打开, 需要使用16进制编辑器打开。
我们用一个16进制编辑器: HxDHexEditor 打开这个class文件:
接下来, 我们来分析一下这个class文件。
魔数
每个 class 文件的头 4 个字节被称为魔数(Magic Number), 它的唯一作用是表示这个文件是一个 class 文件, 固定为 0xCAFEBABE
。
版本号
魔数后面的 4 个字节是 class 文件的版本号: 第 5 和第 6 个字节是副版本号(Minor Version), 第 7 和第 8 个字节是主版本号(Major Version)。
Java 的版本号是从 45 开始的, JDK 1.1 之后的每个 JDK 大版本发布主版本号向上加 1, 高版本的 JDK 能向下兼容以前版本的 class 文件, 但不能运行以后版本的 class 文件。
ClassFileDemo.class文件中的版本号0x0041.0x0000
转换成十进制是 65.0, 即 JDK 21。
常量池
常量池包含了class文件中用到的各种字符串常量、类和接口名、字段和方法名等符号引用,以及字面量