虚拟机执行子系统
第六章、类文件结构
Sun公司以及其他虚拟机提供商发布了许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码,从而实现“一次编写,到处运行”。
各种不同平台的虚拟机与所有平台都统一使用的程序存储格式——字节码(ByteCode)是构成平台无关性的基石。Java语言中的各种变量、关键字和运算符号的语义最终都是由多条字节码命令组合而成的,因此字节码命令所能提供的语义描述能力肯定会比Java语言本身更加强大。因此,有一些Java语言本身无法有效支持的语言特性不代表字节码本身无法有效支持,这也为其他语言实现一些有别于Java的语言特性提供了基础。
一、Class类文件的结构
任何一个Class文件都对应着唯一一个类或者接口的定义信息,但反过来说,类或接口并不一定都得定义在文件里(也可能通过类加载器直接生成)。
Class文件是一组以8位字节为基础单位的二进制流,字节中间没有任何分隔符。根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。
无符号数:属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成字符串值
表:是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“_info”结尾。表用于描述有层次关系的复合结构的数据,整个Class文件本质上就是一张表。
1.魔数与Class文件的版本
每个Class文件的头4个字节称为魔数,值为0xCAFEBABE,他的唯一作用就是确定这个文件是否是一个能被虚拟机接受的Class文件。第五和第六个字节是次版本号,第七和第八个字节是主版本号。
2.常量池
Class文件中第一个出现的表类型数据项目。在常量池的入口需要放置一项u2类型的数据,代表常量池容量计数值(从1开始计数,Class文件中只有常量池的容量是从1开始的,对于其他集合类型一般是从0开始)。
常量池中那个主要存放两大类常量:字面量和符号引用:
字面量:接近于Java语言层面上的常量概念,例如文本字符转、声明为final的常量值等;
符号引用:类和接口的全限定名、字段的名称和描述符、方法的名称和描述符;
常量池中每一项数据都是一个表。表开始的第一个u1类型的标志位,代表这个常量属于哪种常量类型。
3.访问标志
在常量池结束之后,紧接着的两个字节表示访问标志,用于识别一些类或者接口层次的访问信息,包括这个Class是类还是接口、是否定义为public类型、是否定义为abstract类型、是否被声明为final等。
00 21:public 类
4.类索引、父类索引与接口索引集合
类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据的集合,按顺序排列在访问标志之后,Class文件中由这三项数据来确定这个类的继承关系。对于接口索引集合,入口第一项是一个u2类型的数据的接口计数器,存储着该类实现了几个接口。
5.字段表集合
字段表用于描述接口或者类中声明的变量。字段表记录着字段的作用域(public,private,protected)、是实例变量还是类变量(static)、可变性(final)、并发可见性(volatile)、是否可被序列化(transient)、字段数据类型、字段名称。
6.方法表集合
方法表结构一次包括了访问标志、名称索引、描述符索引、属性表集合。
7.属性表集合
。。。
二、字节码指令
Java虚拟机的指令是由一个字节长度(256个)的、代表着某种特定操作含义的数字(操作码),以及跟随其后的参数(操作数)而构成。由于Java虚拟机采用面向操作数栈而不是寄存器的架构,所以大多数的指令都不包含操作数,只有一个操作码。
字节码详情见书P230
1.加载和存储指令
2.运算指令
3.类型转换指令
4.对象创建和访问指令
5.操作数栈管理指令
6.控制转移指令
7.方法调用和返回指令: invoke***
8.异常处理指令
9.同步指令
三、公有设计和私有实现
【公有设计】:Java虚拟机有共同程序存储格式:Class文件格式和字节码指令集。
【私有实现】:虚拟机的实现方式有两种:①将输入的Java虚拟机代码在加载和执行时翻译成另外一种虚拟机的指令集。②将输入的Java虚拟机代码在加载和执行时翻译成宿主机CPU的本地指令集(即JIT代码生成技术)。