类加载过程中的被动引用例子
1 package jvm.part_7; 2 /** 3 * 被动使用类字段演示一: 4 * 通过子类引用父类的静态字段,不回导致子类初始化 5 * @author Administrator 6 * 7 * 只会输出 SuperClass init! 8 *分析:对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过其子类来引用父类中定义的静态字段, 9 *只会触发父类的初始化而不会触发子类的初始化; 10 */ 11 class SuperClass{ 12 static{ 13 System.out.println("SuperClass init!"); 14 } 15 public static final int value = 123; 16 } 17 18 class ChildClass extends SuperClass{ 19 static{ 20 System.out.println("ChildClass init!"); 21 } 22 } 23 public class ConstClass { 24 public static void main(String[] args){ 25 System.out.println(ChildClass.value); 26 } 27 }
上述代码运行之后,只会输出“SuperClass init!”,而不会输出"ChildClass init!",证明子类被又被初始化。
原因:对于静态字段,只有直接定义这个字段的类才会被初始化,因此通过子类来引用父类中定义的静态字段,只会触发父类的初始化而不会触发子类的初始化。
1 package jvm.part_7; 2 3 public class NotInitialization { 4 /** 5 * 被动引用类字段演示二: 6 * 通过数组定义来引用类,不回触发此类的初始化。 7 * @param args 8 * 9 * 没有输出结果,说明数组的定义不会引用类,触发初始化操作 10 */ 11 public static void main(String[] args) { 12 SuperClass[] sca = new SuperClass[10]; 13 } 14 }
上述代码运行之后,没有输出,说明数组的定义并不会触发类的初始化操作;
1 package jvm.part_7; 2 /** 3 * 被动引用类字段演示三: 4 * 常量在编译阶段会存入调用类的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化 5 * @param args 6 * 7 * 结果仅仅输出 hello world ,而不会初始化ConstClass1 init! 静态代码块; 8 * 9 * 分析:因为虽然在java源码中引用了ConstClass1类中的常量HELLOWORLD,但是在编译阶段将此常量的值存储到了NotInitialization1类的常量池中 10 * 实际上最后引用的是自己的常量池中的常量,并不会引入ConstClass1的加载。 11 */ 12 13 class ConstClass1{ 14 static{ 15 System.out.println("ConstClass1 init!"); 16 } 17 18 public static final String HELLOWORLD = "hello world"; 19 } 20 public class NotInitialization1 { 21 22 public static void main(String[] args) { 23 System.out.println(ConstClass1.HELLOWORLD); 24 } 25 26 }
分析:因为虽然在java源码中引用了ConstClass1类中的常量HELLOWORLD,但是在编译阶段将此常量的值存储到了NotInitialization1类的常量池中实际上最后引用的是自己的常量池中的常量,并不会引入ConstClass1的加载。