我们知道,在初始化一个类时,如果它的父类没有进行初始化,那么JVM就会触发其父类的初始化动作。但是,当我们引用类的时候,可不一定会触发其初始化,这种引用类的方式称为被动引用。
看下面的例子:
public class NotInit {
public static void main(String[] args) {
System.out.println(Child.val);
// System.out.println(Father.str);
Father[] father = new Father[4];
System.out.println(Constant.HELLO);
}
}
class Father {
static {
System.out.println("Father init!");
}
public static int val = 100;
// public static String str = "string";
}
class Child extends Father {
static {
System.out.println("Child init!");
}
}
class Constant {
static {
System.out.println("Constant init");
}
public static final String HELLO = "HELLO";
}
见证奇迹的时刻到了!!!程序输出为:
Father init!
100
HELLO
这不科学啊!!!代码中调用了
System.out.println(Child.val);
可是没有竟然没有对Child类进行初始化。这是因为val为静态字段,只有直接定义这个字段的类才会被初始化,故通过子类来引用父类静态字段val,只会触发Father类的初始化,而不会触发Child类的初始化,so 就没有Child类的事。
再来,代码中虽然有
Father[] father = new Father[4];
可是Father类居然没有初始化,这也是情理之中的。这句代码仅仅定义了一个Father类型的一维数组,数组里面什么都没有放!就好比我买了一个可以容纳100L的容器,而且是只能用来装浓硫酸的容器,但是我现在还没把浓硫酸放入容器,所以容器中什么也没有,即是没有初始化。
看官接着往下瞧:
System.out.println(Constant.HELLO);
Constant类没有直接父类,可为何还是没能初始化Constant类。大家也看见了,HELLO是一个常量。常量和一般的变量不一样,因为HELLO是常量,所以Constant类在编译阶段通过常量优化传播,把HELLO所代表的"hello"存储到了NotInit类的常量池中。说人话就是,以后NotInit类对常量Constant.HELLO的引用实际都转化为NotInit类对自身常量池的引用了。在编译结束后,Constant类和NotInit类就劳燕分飞各自走了。
总结是个好习惯!本文描述了类加载过程中的三种被动引用,这些情况下都不会触发相应类的初始化:
一、 通过子类引用父类的静态字段,不会导致子类初始化
二、 通过数组定义来引用类,不会触发该类的初始化
三、 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的那个类,所以也不会触发定义常量的类的初始化
已有 0 人发表留言,猛击->> 这里<<-参与讨论
ITeye推荐