jvm-类加载机制

类加载过程

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(using)、和卸载(Unloading)七个阶段。其中验证、准备和解析三个部分统称为连接(Linking),如下如所示。

  • 加载,是指查找字节流,并据此创建类的过程。
  • 链接
    • 验证,确保被加载的类能够满足java虚拟机的约束条件。
    • 准备,为被加载类的静态字段分配内存。
    • 解析,将符号引用解析为实际引用。如果符号引用指向一个未被加载的类或未被加载类的字段或方法,那么解析将触发这个类的加载(但未必出发这个类的链接和初始化。)
  • 初始化,为标记为常量值的字段赋值,以及执行clinit方法。

clinit(如果直接赋值的静态字段被final所修饰,并且它的类型是基本类型或字符串时,那么该字段便会被java编译器标记成常量,其初始化直接有java虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,则会被java编译器置于同一方法中,并把它命名为clinit)

类的初始化何时会被出发,JVM规范枚举了下述情况:

  1. 当虚拟机启动时,初始化用户指定的主类。
  2. 当遇到用以新建目标实例的new指令时,初始化new指令的目标类。
  3. 当遇到调用静态方法的指令时,初始化该静态方法所在的类。
  4. 当遇到访问静态字段的指令时,初始化该静态字段所在的类。
  5. 子类初始化会触发父类的初始化。
  6. 如果接口定义了default方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化。
  7. 使用反射api对某个类进行反射调用时,初始化这个类。
  8. 当初次调用methodHandle实例时,初始化该MethodHandle指向的方法所在的类。