模式切换
类文件结构
概述
在 Java 语言诞生之初就提出了“一次编译,到处运行”的理念,这也是 Java 语言跨平台的重要特性之一。之所以能够实现“与平台无关”的理想,是因为代码编译的结果从本地机器码转变为字节码的存储格式的发展。
不论什么平台,只需要最终编译出遵循《Java 虚拟机规范》的字节码文件,就可以在任何支持 Java 虚拟机规范的平台上运行。各种不同平台的 Java 虚拟机,以及所有平台都统一支持的程序存储格式 ———— 字节码(Byte Code)是构成平台无关性的重要基石。
随着技术的不断进步,“语言无关性”正在被开发者所重视。在 Java 技术发展之初,设计者就考虑让其他语言运行在 Java 虚拟机上,因此他们在发布规范时,特意将 Java 的规范拆分成了《Java 语言规范》(The Java Language Specification)和《Java 虚拟机规范》(The Java Virtual Machine Specification)两部分。
在 2018 年,基于 HotSpot 虚拟机扩展而来的 GraalVM 项目,支持了多种语言的运行,包括 Java、Scala、Kotlin、Groovy、JavaScript、Ruby、Python 等。
实现语言无关性的基础仍然是虚拟机和字节码存储格式。Java 虚拟机不与任何语言绑定,只需要提供“Class 文件”这种特定的二进制文件格式。这种文件格式包括了虚拟机指令集、符号表、字节码等信息。
图 Java 虚拟机提供的语言无关性
Class 类文件的结构
Class 文件结构是 Java 虚拟机重要的基础之一。Java 技术之所以能够保持着非常良好的向后兼容性,Class 文件结构的稳定功不可没。
Class 文件是一组以字节码为基础单位的二进制流。根据《Java 虚拟机规范》中的规定,Class 文件格式采用一种类似于 C 语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。
- 无符号数属于基本的数据类型,以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节和 8 个字节的无符号数。无符号数可以用来描述数字、索引引用、数量值或者按照 UTF-8 编码构成的字符串。
- 表是由多个无符号数或者其他表作为数据项构成的复合数据类型。为了便于区分,所有表的命名都习惯性地以 “_info” 结尾。表用于描述有层次关系的复合结构的数据,整个 Class 文件本质上也可以视为一张表,这张表是由下表所示的数据项按照严格的顺序排列而成。
表 Class 文件格式
无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式。这种形式的数据项也是表的一种,只不过在特定场景下称为表的集合。
Class 结构不像 XML 等描述语言那样,有明确的开始和结束标签,而是没有任何的分隔符号。在上表的数据项,无论是顺序还是数量,甚至数据存储的字节序(Byte Ordering,Class 文件中字节序为 Big-Endian)都是严格固定,哪个字节代表什么含义,长度是多少,先后顺序如何,都不能改变。