java 类的主动引用和被动引用

本贴最后更新于 1966 天前,其中的信息可能已经天翻地覆

本文参考《深入理解 JAVA 虚拟机》第 2 版,此书 JDK 版本为 1.7。

主动引用

java 类的初始化阶段,虚拟机规范严格规定了 5 种情况必须立即对类进行初始化。

  1. 遇到 new、getstatic、putstatic 或 invokestatic 这 4 条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。
  2. 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。
  3. 当初始化一个类时,如果发现其父类没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要制定一个要执行的主类(包含 main()方法的那个类),虚拟机会先初始化这个类。
  5. 当使用 JDK1.7 的动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_geStatic、REF_putStatic、REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

被动引用

除了上述 5 种场景,其他所有类的方式都不会触发初始化,称为被动引用。下面举 3 个例子来说明。

1、子类引用父类静态变量

public class SuperClass{

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

	public static int value = 123;

}

public class SubClass extends SuperClass{

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

public class InitTest{
	
	public static void main(String[] args){
		System.out.println(SubClass.value);
	}

}
//执行结果
//SuperClass init!
//123

结论:对于静态变量,只有对应这个静态变量的类才会被初始化,通过子类调用只会使父类初始化,子类不会初始化。

2、创建对象数组

public class InitTest{

	public static void main(String[] args){ 
		SuperClass[] array = new SuperClass[10];
	}

}
//运行后没有输出

结论:创建对象数组不会使对象的类初始化。注:会使数组类初始化,在这个例子中,数组类是"[L 包名.SuperClass"

3、调用类中的常量


public class ConstClass{

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

	public static int value = 123;

}

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

}
//执行结果
//123

结论:调用对象常量不会触发类初始化。书中解释:在编译阶段通过常量传播优化,已经将此常量的值“123”存储到了 InitTest 类的常量池中,以后 InitTest 对常量 ConstClass.value 的引用实际都转换为 InitTest 对自身常量池的引用。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3187 引用 • 8213 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...