笔记JVM —— Class 类文件结构

任何一个Class文件都对应着唯一一个类或接口的定义信息,但反过来说,类或接口并不一定都得定义在文件里(可以通过类加载器直接生成)

Class 文件是一组以8位字节为基础单位的二进制流,当遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储

Class 文件格式采用一种类似于C语言结构体系的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。无符号数属于基本数据类型,以u1、u2、u4、u8来分别表示1个字节,两个字节,4个字节,8个字节的无符号数。表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性的以“_info"结尾。

每个Class 文件的头4个字节称为魔数,它的唯一作用是确定这个文件是否为一个能够被虚拟机接受的Class文件,紧接着魔数的4个字节是主版本号,第5和第6个字节是次版本号,第7和第8个字节是主版本号。虚拟机拒绝执行超过其版本号的Class文件。

紧接着主版本号之后是常量池入口,常量池可以理解为Class文件之中的资源仓库,它是Class 文件中与其他项目关联最多的数据类型,也是占用Class文件最大的数据项目之一,同时他还是在Class文件中第一个出现的表类型数据项目。

常量池的入口需要放置一项u2类型的数据,代表常量池容量计数器,值从1开始。

常量池中主要存放两大类常量:字面量和符号引用。

UTF-8缩略编码与普通UTF-8编码的区别是:从‘\u0001’到'\u007f'之间的字符的缩略编码使用一个字节表示,

 

 

访问标志

在常量池结束后,紧接着的两个字节代表访问标志,这个标志用于识别一些类或者接口层次的访问信息。

笔记JVM —— Class 类文件结构

类索引、父类索引、与接口索引集合

类索引和父类索引都是一个u2类型的数据,而接口索引集合是一组u2类型的数据结构。Class文件中这三项数据来确定这个类的继承关系。类索引用来确定这个类的全限定名,父类索引用来确定这个类的父类全限定名。

字段表集合

字段表用于描述接口或者类中声明的变量。字段包括类级变量以及实例级变量,但不包括在方法内部声明的局部变量。

(ps:扩展概念:全限定名,简单名称,方法和字段的描述符)

方法表集合

笔记JVM —— Class 类文件结构

方法里的代码存放在方法属性表集合中一个名为”Code“的属性里面

属性表集合

Code 属性:代码经过Javac编译器处理后,最终变为字节码指令存储在Code属性内.Code属性出现在方法表的属性集合里,但并非所有的方法表都必须存在这个属性

Exceptions属性:列举方法中可能抛出的受查异常,也就是方法描述时在throws关键字后面列举的异常。

LineNumberTable属性:描述Java源码行号和字节码行号之间的对应关系

LocalVariavleTable属性:描述栈帧中局部变量表中的变量与Java源码中定义的变量之间的关系。

SourceFile属性:记录生成这个Class文件的源码文件名称。

ConstantValue属性:通知虚拟机自动为静态变量赋值。只有被static关键字修饰的变量才可以使用这个属性。对于非static类型的变量的赋值实在实例构造器<init>方法中进行的,而对于类变量,则有两种方式可以选择:类构造器<clinit>方法中或使用Constatnlaue属性。

InnerClasses属性:用于记录内部类与宿主类之间的关联。

Deprecated、Synthetic属性:都属于标志类型的布尔属性,只存在有何没有的区别,没有属性值的概念。

StackMapTable属性

Signature属性:记录泛型类型。

BootStrapMethods属性:用于保存invokedynamic指令引用的引导方法限定符。

字节码指令

由一个字节长度的、代表着某种特定操作含义的数字以及跟随其后的零至多个代表此操作所需要参数构成

 

 

 

 

 

 

异常处理指令:Java程序中显示抛出异常的操作都由athrow指令来实现,Java虚拟机中处理异常由异常表来完成。

同步指令: