虚拟机类加载机制(主动应用和被动引用)

    虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的java类型,这就是虚拟机的类加载机制。

虚拟机类加载机制(主动应用和被动引用)_第1张图片

虚拟机规范规定了有且仅有四种情况必须立即对类进行初始化:

(1)遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。

(2)使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发初始化。

(3)当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

(4)当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类

上面的情况称为对一个类进行主动引用。除此之外所有引用类的方式,都不会触发初始化,称为被动引用。

被动引用情形一:

package com.java.initialization;

public class SuperClass {

	static {
		System.out.println("SuperClass init");
	}
	
	public static int value = 123;
}
package com.java.initialization;

public class SubClass extends SuperClass {

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

package com.java.initialization;

public class NotInitialization {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		System.out.println(SubClass.value);
	}

}
结果:
SuperClass init
123

这个很奇怪吧!只输出了SuperClass init ,对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。

被动引用情景二

package com.java.initialization;

public class ConstClass {

	static {
		System.out.println("ConstClass inti ");
	}
	
	public static final String name = "name";
}

package com.java.initialization;

public class NotInitialization {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		
		System.out.println(ConstClass.name);
	}

}
结果:

name

这有很奇怪了!没有输出“ConstClass inti ”,这是因为constClass类中的常量name,在编译阶段将此常量的值存储到了NotInitialization类的常量池中,实际上NotInitialization的class文件之中没有constClass类的符号引用入口,者各类在编译成class之后就不存在任何联系了。

注:当一个类在初始化时,要求其父类全部都已经初始化过了,但是一个接口在初始化,并不要求其父类接口全部都完成了初始化,只有在真正使用到父接口的时候才会初始化。
被动引用情景三:

通过数组定义类应用类:ClassA [] array=new ClassA[10]。触发了一个名为[LClassA的类的初始化,它是一个由虚拟机自动生成的、直接继承于Object的类,创建动作由字节码指令newarray触发。

参考《深入理解java虚拟机》













你可能感兴趣的:(虚拟机类加载机制(主动应用和被动引用))