Java虚拟机使用某个类的过程,可分为七个阶段:

加载 - 验证 - 准备 - 解析 - 初始化 - 使用 - 卸载


本文只介绍在什么情况下对类进行初始化。

Java虚拟机规范对何时进行类的初始化做了严格规范,有且只有四种情况:

1. 虚拟机启动时,指定的主类。

   包含main方法的类。

2. 遇到new、getstatic、putstatic、invokestatic四条指令时。

   new:使用new关键字实例化对象。

   getstatic:读引用一个类的静态字段。

   putstatic:写引用一个类的静态字段。

   invokestatic:调用一个类的静态方法。

3. 初始化一个类时,先初始化其父类。

   接口则不是,只有真正引用到了父接口时,才会初始化。

4. 对类进行反射调用时。


测试代码:

MainClass:

package com.xuefeng.jvm.load;

/**
 * 初始化类的时机
 * 1. 虚拟机启动时指定的主类
 * 2. new某类的对象时、引用某类的static变量时、设置某类的变量时、调用某类的static方法时
 * 3. 初始化一个类时,先初始化其父类。接口则不是,真正使用到了父接口时,才会初始化父接口。
 * 4. 通过反射调用某类时
 * @author xuefeng
 *
 */
public class MainClass {

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

	// 1
	public static void main(String[] args) throws ClassNotFoundException {
//		// 2
//		System.out.println("SuperClass.F_V1 : " + SuperClass.F_V1);
//		System.out.println("SuperClass.v1 : " + SuperClass.v1);

//		// 3
//		SubClass s1 = new SubClass();
		
		// 3.1  如果通过子类名引用父类的static变量,是否会触发子类的初始化?
		// 这取决于具体的虚拟机实现,Sun HotSpot虚拟机此时是不会触发子类的初始化的。
		System.out.println(SubClass.v1);

		// 4
		Class.forName("com.xuefeng.jvm.load.SubClass");
	}

}

SuperClass:

package com.xuefeng.jvm.load;

public class SuperClass {
	static {
		System.out.println("SuperClass init.");
	}

	/**
	 * 引用v1时,会初始化SuperClass
	 */
	public static int v1 = 1;
	
	/**
	 * 引用F_V1时,不会初始化SuperClass
	 * static final的变量,已经在编译器放到了常量池里
	 */
	public static final int F_V1 = 1;
}

SubClass:

package com.xuefeng.jvm.load;

/**
 * 
 * @author xuefeng
 *
 */
public class SubClass extends SuperClass {
	static {
		System.out.println("SubClass init.");
	}
}


Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐