美文网首页
7.2类加载的时机

7.2类加载的时机

作者: 怡红快绿 | 来源:发表于2018-12-18 17:03 被阅读0次
    类的生命周期.png

    加载、验证、准备、初始化、卸载这五个阶段的顺序是确定的,类的加载过程必须按照这种顺序按部就班地开始,而解析阶段有可能在初始化阶段之后才开始,这是为了支持Java的动态绑定。

    虚拟机并没有强制约束“加载”阶段的开始时机,而是交给虚拟机的具体实现来自由把握。但是对于初始化阶段,则严格规定有且只有五种情况必须对类进行初始化:
    1、遇到new、getstatic、putstatic或invokestatic这四条指令时,如果类没有初始化,则必须先触发初始化动作。对应的场景分别是:

    • 使用new关键字实例化对象
    • 读取或设置一个类的静态字段(被final修饰的静态字段除外)
    • 调用类的静态方法

    2、使用java.lang.reflect包的方法对类进行反射的时候,如果类没有进行过初始化,则需要先触发其初始化。
    3、当初始化一个类的时候,如果发现它的父类还没有初始化,则要先初始化父类。
    4、当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个类。
    5、当使用JDK1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄对应的类没有初始化,则要先触发其初始化。

    这五种场景中的行为称为对一个类进行主动引用。除此之外,所有对类的引用方式都不会触发初始化,称为被动引用。

    子类引用父类静态字段.png

    运行Subclass.value,只会输出"SuperClass init!"。对于静态字段,只有直接定义这个字段的类才会被初始化,因此本例中只有父类被初始化。

    通过数组定义来引用类.png

    运行之后发现没有输出"SuperClass init!",说明没有触发SuperClass类的初始化阶段。

    image.png

    运行之后没有输出"ConstClass init!",这是因为静态常量在编译期间,已经将ConstClass.HELLOWORLD的值放入NotInitialization类的常量池中,所以对HELLOWORLD的引用实际已经转化为NotInitialization类对自身常量池的引用,实际上两个类在编译完成之后就不存在任何联系了。

    接口的加载过程与类加载过程稍微有点不同,接口也有初始化过程,但是与类有所区别的是前面提到的5种情况中的第三种:当一个类需要初始化时,需要保证所有的父类都被初始化,但是一个接口在初始化时,并不要求父接口都完成了初始化,只有真正使用到父接口的时候才会初始化(例如引用接口中的常量)。

    相关文章

      网友评论

          本文标题:7.2类加载的时机

          本文链接:https://www.haomeiwen.com/subject/nrcckqtx.html