java类初始化两三事

过完整本深入理解Java虚拟机后,发现对类的初始化加载仍然是一知半解的。记得昨晚在极客时间上看到刘超老师在Java性能调优21章写的Demo时,对Demo的输出顺序感到有些疑惑。便在IDE上进行了测试。
父类:

public class Parent {
        public static String parentStr = "parent static String";
        static{
            System.out.println("parent static fileds");
            System.out.println(parentStr);
        }
        public Parent(){
            System.out.println("parent instance initialization");
        }
}

子类:

public class Sub extends  Parent{
    public static String subStr = "sub static String";
    static{
        System.out.println("sub static fileds");
        System.out.println(subStr);
    }
    public Sub(){
        System.out.println("sub instance initialization");
    }
    public static void main(String[] args){
//        System.out.println("sub main");
//        new Sub();
    }
}

因为看到输出是先打印出父类静态块->子类静态块->sub main()->父类构造函数->子类构造函数。
原本我的猜想是:sub main是在new显示初始化后输出的,但看结果并不是这样,所以猜想应该是在Sub类中的main函数先触发了虚拟机对Sub类的初始化。并且虚拟机发现Sub类的父类仍未初始化;
所以,先对Parent类进行了初始化,按静态块在程序中的位置,顺序输出Parent静态块的内容。
再对Sub类进行初始化,同样安装静态块在程序中的位置,顺序输出Sub块的内容。
而后System.out.println(“sub main”);再进行了打印输出。
执行到new一个子类Sub()时,先执行父类的构造方法,再执行子类的构造方法。所以产生了如上的输出。
其实这个在周志明老师写的《深入理解Java虚拟机》中有过详细介绍:虚拟机规范中规定了有且只有5中初始化方式(P210页-P211页),其中的3、4两种情况。
回看的时候又发现了一些新的东西:

1.被动引动

  1. 对于静态字段,只有直接定义了这个字段的类才会被初始化。也就是说:通过子类直接调用父类的静态字段,是不会触发子类的初始化。但虚拟机规范未明确规定该动作是否会触发子类的加载和验证,因此不同的虚拟机可能会有不同的实现。其中HotSpot虚拟机中,该操作会导致子类的加载。经在IDEA上JDK8的环境下验证后,确实有此表现,同时猜想我电脑上的JVM默认采用的是HotSpot虚拟机~代码比较简单,就不贴上来占地方啦,结果如图。其中InvokeStatic是父类,其中有静态块,静态方法,InvokeSubStatic继承了InvokeStatic,里面有一个静态块。另有Parent,在main函数中通过子类调用了父类的静态方法。可以看出:子类的静态块并没有输出,但确实有加载子类。要看到这个结果需要配置JVM参数:-XX:+TraceClassLoading。结果如图:
  2. 数组定义引用类,或者说是构建该类的数组,不会触发该类的初始化。
  3. 常量(static final)在编译阶段存入**调用类(仅调用被调用类的常量)**的常量池中,在编译阶段通过常量传播的优化,将常量的值传入到了调用类的常量池中,调用类对常量的引用,实际都转化成了调用类对自身常量池的引用。因此其实在编译后,调用类和被调用类就不存在任何联系了。

2.接口的加载过程

接口也有初始化过程,和类是一致的,编译器会为接口生成()类构造器,用于初始化接口中定义的成员变量;接口仅仅在真正使用到的时候(如引用接口中定义的常量)才进行初始化,并不会像类加载一样,要求其父类全被初始化。

当初看的时候懵懵懂懂的,回看几遍并动手时间后才大概了解了这些文字的大体意思。收获颇丰。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值