深入理解Java虚拟机

虚拟机类加载机制--类加载的时机

2018-08-08  本文已影响4人  gluawwa

  类从被加载到虚拟机内存中开始,到卸载出虚拟机内存为止,包括加载、验证、准备、解析、初始化、使用、卸载七个阶段。其中验证、准备、解析三个部门统称为连接。
  Java虚拟机规定有且只有五种情况必须立即进行类初始化。
    1、遇到new、getStatic、putStatic、invokeStatic这四条字节码指令时;
    2、使用java.lang.reflect包的方法对类进行反射调用时;
    3、当初始化一个类,发现其父类尚未初始化时,需先初始化其父类。接口与类稍有不同,接口在初始化时,并不要求其父接口完成初始化,只有真正使用到父接口(如引用父接口中定义的常量)时才会初始化;
    4、虚拟机启动时,初始化含有main()方法的子类;
    5、当使用jdk1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果是REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个句柄对应的类没有被初始化;
    除此之外,所有饮用类的方法不会触发初始化,称为被动引用。

/**
 * 被动引用示例一,通过子类引用父类的静态字段,不会引发子类初始化
 * 对于静态字段 ,只有定义这个字段的类会被初始化
 * 输出结果:superClass init
 *                     123
 */
class SuperClass {
    public static int value = 123;

    static {
        System.out.println("superClass init");
    }
}

class SubClass extends SuperClass {
    static {
        System.out.println("subClass init");
    }
}


public class ClassLoad {
    public static void main(String[] args) {
        System.out.println(SubClass.value);
    }
}
/**
 * 被动引用示例二,通过数组定义来引用类不会出发此类的初始化
 * 输出结果:无
 */
public class NonInitialization {
    public static void main(String[] args) {
        SuperClass[] superClasses = new SuperClass[10];
    }
}
/**
 * 被动引用示例三,常量在编译阶段会放入调用类的常量池,本质上没有直接引用到定义常量的类 输出结果:hello
 */
class ConstClass {

    public static final String HELLO = "hello";

    static {
        System.out.println("constClass init");
    }
}

public class ConstClassLoad {
    public static void main(String[] args) {
        System.out.println(ConstClass.HELLO);
    }

}
上一篇 下一篇

猜你喜欢

热点阅读