类加载过程

Spring Wu 745 2021-02-03

加载

  • 主要作用:把编译好的class文件加载到内存中

这个阶段主要是编译器把Java代码编译为class文件后,在启动jvm进程时,jvm会把class文件转为二进制数据存在内存中,然后在方法区创建一个对应Class对象,该对象是访问被加载过后的class对象各种数据的入口。

验证

  • 主要作用:验证class(存在内存中的二进制码)是否符合当前jvm版本的规范,已经代码是否符合jvm的规范。

当class文件被加载到内存后,先检验是否符合当前jvm版本规范,因为不同版本的jvm规范是不一致的,新的jvm可能会抛弃或禁用一些指令。

还要检验代码是否符合jvm规范,比如当我们调用一个add(int i)方法。该方法需要传入一个int类型的参数,但却传入了String类型的参数,此时校验不会通过。

准备

  • 主要作用:为类变量初始化内存和值。

通过jvm规范验证后,jvm接下来就初始化类变量内存和值,就是以static修饰的类变量。当类变量以static final修饰的时候,初始化的值是由用户指定的值。比如:

private static final int i = 10

private static int j = 2

当初始化变量i时,会分配i的内存以及值10

当初始化变量j时,会分配j的内存,并把j的值初始化为零值,也就是0。并不是用户指定的2

原因是:当变量被修饰为final后,表示该变量不可变,并且不可被继承。也就是变量的内存地址以及值无法被改变,那么用户最初赋予final修饰的变量的值,也就是最终的值,肯定不会被改变,所以在初始化时,jvm也顺理成章的把final修饰的变量值初始化为用户指定的值。

解析

  • 主要作用:主要针对类、接口、方法、等进行解析。将常量池的符号引用替换为直接引用的过程。也就是将虚拟的引用关系替换为真实的内存引用关系。

符号引用:记录了类相关信息,如方法名,方法参数等,当第一次运行该方法时,会通过符号引用找到方法,然后把符号引用替换为直接引用。

直接引用:直接引用就是内存的偏移量,虚拟机通过偏移量可以直接找到内存上该方法字节码的起始位置。

初始化

  • 主要作用:Java代码真正运行的阶段,在这个阶段,jvm会根据代码的执行顺序初始化类对象。

何时触发初始化:

  1. new对象的时候。当new一个对象的时候,如果该类没有被初始化过,则会初始化该类后。再进行new操作。
  2. 当读取或设置一个static修饰的变量时会进行初始化,有一种情况除外,就是当static变量以final修饰时的时候,不会被初始化,因为该常量已经在准备阶段被初始化到了常量池中。还有当调用的方法为static修饰的时候,调用方法所在类,也会被初始化。
  3. 当使用反射调用类方法时,调用的类会被初始化。
  4. 当虚拟机启动后,用户指定了主类。也就是main方法类,该类会被优先初始化。
  5. 当一个类继承了父类后,它的父类需要先初始化后,才会初始化本类。

使用

当jvm执行完初始化阶段后,jvm就从入口开始执行用户的程序代码。

卸载

当用户代码被jvm执行完毕后,jvm会销毁相关的class对象。最后退出内存。