第6章 类文件结构
6.1 概述
字节码和二级制本地机器码(Native Code)是用来存储程序编译后的结果的,是二种程序存储结构。
6.2 无关性的基石
这里说的无关性,分为:平台无关性和语言无关性。
-
平台无关性:JVM和字节码是构成平台无关性的基石。
-
语言无关性:所谓语言无关性是说,不是只有Java语言编写的程序才能运行在JVM上,其他语言编写的程序也可以运行在JVM上。构成语言无关性的基石同样是JVM和字节码。
Java虚拟机提供的语言无关性如图:
3. JVM不与编程语言绑定,它只与Class文件这种特定的二进制文件格式所关联。
6.3 Class文件的结构
- Class文件是一个以8位字节为基本单位的二进制流。
- Class文件是采用一种类似C语言结构体的伪结构来存储数据的,所存储的数据只有两类:无符号数和表。
-
无符号数:
无符号数属于基本数据类型,可以用来表示数字、索引引用、数量值、UTF-8编码的字符串。我们可以使用u1、u2、u4、u8分别来表示1个字节、2个字节、4个字节、8个字节的无符号数。
-
表:
表是由多个无符号数或其他表作为数据项而组成的复合数据类型,通常以“_info”来结尾。
-
- Class文件中头4个字节称为魔数(Magic Number),作用是基于这个魔数来判断当前虚拟机是否能接收这个Class文件。之所以采用这种方式来判断,而不是采用文件扩展名,也是出于安全的考虑,因为文件扩展名可以被随意修改。
- 紧跟魔数的后四个字节标识了Class文件的版本,5、6是次版本号(Minor Version),7、8是主版本号(Major Version)
- 紧跟主版本号之后的是常量池入口。常量池中的每一项常量就是一张表。常量池中主要存放两类常量:字面量和符号引用。
-
字面量
例如:文本字符串、被final修饰的常量值
-
符号引号
分为以下三类:
-
类和接口的全限定名(Fully Qualified Name)
-
字段的名称和描述符(Descriptor)
这里的描述符是用来描述字段的数据类型。
-
方法的名称和描述符
这里的描述符是用来描述方法的参数(个数、类型、顺序)和返回值。
-
-
- Java代码在进行javac编译的时候,不会像C和C++那样有“连接”步骤,而是在虚拟机进行类加载的时候进行动态连接。
- 类的继承关系是通过类索引、父类索引、接口索引集合这三项数据来确定的。
- 方法表集合
- 一个方法对应一个方发表,方发表的结构包括:访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)。
- 方法表中有一个属性表集合,其中有一个Code属性是用来存放方法编译后的字节码,这个属性并不是每个方法都有,例如:接口中的方法和抽象类中的抽象方法就没有这个属性。
- Code属性中字节码指令之后是这个方法的显示异常处理表(简称异常表)集合,异常表对于Code属性来说不是必须的(如果代码中没有异常处理的逻辑就没有这个异常表了)。编译器是采用显示异常处理表来实现Java异常和finally处理机制的,而不是通过简单的跳转命令。
- 属性表集合中还有一个Exception属性,这个属性与Code属性同级,与上边提到的显示异常处理表不同,Exception属性是用来列出方法的要抛出去的受检异常(Checked Exception),也就是方法上throws关键字后边跟着的异常。
- 一个方法对应一个方发表,方发表的结构包括:访问标志(access_flags)、名称索引(name_index)、描述符索引(descriptor_index)、属性表集合(attributes)。
6.4 字节码指令简介
- Java虚拟机的指令是由操作码(Opcode,一个字节)和操作数(Operands,即操作码的参数)组成的。
- 由于Java虚拟机是基于操作数栈而不是寄存器的架构,所以大多数指令没有操作数(操作数都存放在操作数栈中了),只有一个操作码。
- 操作码的长度为一个字节(能表示的范围是0~255),即指令集中的操作码总数不能超过256。
- 加载和存储指令
- 加载指令是用在从局部变量表中将数据加载到操作数栈中。
- 存储指令是将操作数栈中的数据存储到局部变量中。
- 运算指令
将两个操作数栈中的数据进行某种特定的运算,并将运算的结果在存储到操作数栈的栈顶。
运算指令分为:整型数据运算指令和浮点数据运算指令。 - 同步指令
Java虚拟机支持方法级同步和一段指令序列同步,这两种同步结构都是通过管程(Monitor)来实现的。- 方法级同步
方法级同步是隐式的,不需要字节码指令来支持,是在方法调用和返回操作中实现的。 - 一段指令序列同步
同步一段指令序列,通常使用的是synchronized语句块来实现的,synchronized关键字是通过指令集中monitorenter和monitorexit两个指令来支持的。
- 方法级同步
上一篇:《深入理解JAVA虚拟机(第2版)》- 第3章 - 学习笔记
下一篇:《深入理解JAVA虚拟机(第2版)》- 第7章 - 学习笔记