Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种微结构中只有两个数据类型:
- “无符号数”:以 u1、u2、u4、u8 分别表示 1 个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引饮用、数量值或者按照 UTF-8 编码构成字符串值
- “表”:由多个无符号数或者其他表作为数据项构成的复合数据类型。
1. 魔数(Magic Number)
位置为第 1-4 个字节,每个 Class 文件的头 4 个字节被称为魔数(Magic Number),它的唯一作用是确定这个文件是否为一个能被虚拟机接受的 Class 文件。魔数=0xCAFEBABE
2. 次版本号(Minor Version)
位置为第 5-6 个字节
3. 主版本号(Major Version)
位置为第 7-8 个字节,Java的版本号是从45开始的,JDK 1.1之后 的每个JDK大版本发布主版本号向上加1(JDK 1.01.1使用了45.045.3的版本号)
高版本的 JDK 能向下兼容以前版本的 Class 文件,但不能运行以后版本的 Class 文件,因为虚拟机会拒绝执行超过其版本号的 Class 文件。
4. 常量池
常量池中主要存放两大类常量
- 字面量(Literal),接近 Java 语言的常量概念,如文本字符串、被声明为 final 的常量值
- 符号引用(Symbolic References),接近编译原理方面的概念,主要包括以下几类常量:
- 被模块导出或者开放的包(Package)
- 类和接口的全限定名(Fully Qualified Name)
- 字段的名称描述符(Descriptor)
- 方法的名称和描述符
- 方法句柄和方法类型(Method Handle、Method Type、Invoke Dynamic)
- 动态调用点和动态常量(Dynamically-Computed Call Site、Dynamically-Computed Constant) 常量池特点:
- 表类型
- 常量池中常量的数量不固定,所以常量池的入口放置了一项 u2 类型的数据,代表常量池容量计数器(constant_pool_count),这个容量计数从 1 开始。 Class 文件结构中只有常量池的容量计数是从 1 开始,其他集合如:接口索引集合、字段表集合、方法表集合等的容量计数都从 0 开始。
5. 访问标志(access_flags)
占用 2 个字节,用于识别一些类或者接口层次的访问信息,如:这个 Class 是类还是接口、是否定义为 public 类型、是否定义为 abstract 类型等。
6. 类索引、父类索引与接口索引集合
- 类索引(this_class):一个 u2 类型的数据
- 父类索引(super_class):一个 u2 类型的数据
- 接口索引集合(interfaces):一组 u2 类型的数据的集合
7. 字段表集合(field_info)
用于描述接口或者类中声明的变量。
8. 方法表集合
属性表集合(attribute_info):Class 文件、字段表、方法表都可以携带自己的属性表集合,以描述某些场景专有的信息