虚拟机类加载机制--类加载的时机
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);
}
}