JVM类加载时机

类加载过程简述:

Java虚拟机把描述类的内容从class文件中加载到虚拟机内存中,对其校验、转换解析、初始化。最终形成可以被虚拟机直接使用的java类型,此过程成为虚拟机的类加载过程

 

类加载时机

 

类的生命周期:

虚拟机中类的生命周期从被加载到虚拟机内存中开始,卸载出内存为止。总共包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段。其中验证、准备、解析三阶段被称为连接阶段。

各阶段执行时机:

加载、验证、准备、初始化、卸载五个阶段的执行顺序是固定不变的,其中加载、验证、准备三步必须在初始化之前开始,解析阶段可能会在初始化之后开始。这些阶段通常都是交叉混合进行的,可能在执行一个阶段时会激活、调用其他阶段。

主动引用:

Java虚拟机规范中并未规定何时开始执行加载阶段,但是有6种情况下必定会触发初始化阶段。

  1. 遇到new、getStatic、putStatic、invokeStatic四个指令时,若该类未初始化则触发其初始化。以下为典型场景:
    1. 使用new指令对类实例化时
    2. 调用、设置一个类型的静态字段时(被final修饰过的或者在编译阶段就将结果存入常量池中的静态字段除外)
    3. 调用一个类型的静态方法时
  2. 使用java.lang.reflect包中的方法对类进行反射调用时,若该类未初始化则触发其初始化
  3. 对类进行初始化时先检查该类父类是否初始化,若未初始化则触发其初始化
  4. 虚拟机启动时,需要用户指定一个主类,并将其初始化(包括main()的类)
  5. JDK7时,如果一个java.lang.invoke.MethodHandle实例的解析结果为REF_getStatic、REF_putStatic、REF_invokeStatic、REF_newInvokeSpecial四种方法句柄时,如果该句柄所对应的类未初始化则触发其初始化
  6. 如果一个接口中的方法被定义为JDK8中的默认方法(被default所修饰的方法)时,若该接口的实现类即将初始化则需先将该类进行初始化

被动引用:

有且仅有以上6种情况会对类进行主动初始化,除此之外的所有类型都不会被主动初始化

  1. 子类引用父类的静态字段,不会触发子类的初始化
  2. 用数组定义的引用类,该引用类不会触发初始化
  3. 常量在编译阶段时存入调用类的常量池中,并没有直接引用定义常量的类,不会对定义常量的类触发初始化

类和接口加载时的区别

上述所说的类描述比较笼统,实际上在接口加载时与类加载时是有所区别的,在有且仅有的6中主动引用中的第三种:在对类进行初始化之前,先对其父类进行初始化,在对接口初始化时,不会强制其所有父接口初始化,只有用到这个父接口时才会对其初始化

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章