一个.class文件定义了JVM中一个类型,包括域、方法、继承信息、注解和其他元数据。规范中对类文件的格式有详细描述,任何想在JVM上运行的语言都必须遵守。
JVM的目的是使用类文件并执行其中的字节码。要实现这个目的,JVM必须以字节流的方式取出类文件中的内容,并将其转换成可用的格式加入运行状态中。这个分两步走的过程被称为加载和连接,但连接又被分解为几个子阶段。
加载
这个过程首先要读取构成类文件的字节数据流并给类的表现形式解冻。该过程一开始是创建一个字节数组,其内容通常是从文件系统中读取的,然后产生所加载的类对应的Class对象。在这个过程中会对类做一些基本检查,但在加载过程结束时,Class对象还不成熟,所以类也不可用。
连接
加载完成之后,类必须被连接起来,这一步骤分为三个子阶段 验证、准备、解析。验证阶段证实类文件符合预期,不会引起系统的运行时错误或其他问题。之后是类的准备阶段,在类文件中引用的其他类型全部都要定位到,以确保该类已准备就绪。连接步骤中各子阶段的相互关系 如下图
验证
验证是一个非常复杂的过程,它分为几个步骤,首先是完整性检查,这实际上是加载过程中的一部分,会确保类文件格式良好,可以连接接着是检查常量池中的符号信息是自相一致的,并要遵守常量的基本行为准则。其他不涉及代码的静态检查也要在这一阶段完成,比如检查final方法有没有被重写。之后是验证中最复杂的部分,方法的字节码检查,要检查字节码行为良好,并且不会试图摆脱VM的环境控制,下面是一些主要的检查
- 是否所有的方法都遵守访问控制关键字的限定
- 方法调用的参数个数和静态类型是否正确
- 确保字节码不会试图滥用堆栈
- 确保变量使用之前被正确初始化了
- 检查变量是否仅被赋予恰当类型的值
准备
类的准备包括分配类存和准备好初始化类中的静态变量,但不会现在初始化变量,也不会执行任何VN字节码
解析
解析会初始VM检查类文件中所引用的类型是不是都是已知的类型。如果有运行时位置的类型,那他们也需要被加载进来。这行可见的未知类型会再次引发类加载过程。一旦需要加载的其他类型全被定位并解析完成,VM就可以初始化那个最初要加载的类。这时候所有的静态变量都可以被初始化,所有的静态初始化代码块都会运行。现在你运行的字节码就是来自新加载进来的类里的。这一步完成之后,所有的类就已全部完成,类也可以使用了。