java类加载中不会触发初始化的被动引用

我们知道,在初始化一个类时,如果它的父类没有进行初始化,那么JVM就会触发其父类的初始化动作。但是,当我们引用类的时候,可不一定会触发其初始化,这种引用类的方式称为[size=medium][color=red]被动引用[/color][/size]。
看下面的例子:
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类就劳燕分飞各自走了。

总结是个好习惯!本文描述了类加载过程中的三种被动引用,这些情况下都不会触发相应类的初始化:
[size=large][color=red]一、 通过子类引用父类的静态字段,不会导致子类初始化
二、 通过数组定义来引用类,不会触发该类的初始化
三、 常量在编译阶段会存入调用类的常量池中,本质上并没有直接引用到定义常量的那个类,所以也不会触发定义常量的类的初始化[/color][/size]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值