Java Initialization Order

本文简述Java初始化过程的一些知识点,属于个人学习总结,能力有限,还望各位大神多多指点。

这里有一组类用于展示类的初始化过程。

这个类没有用到,所以实际上不会被加载。

package com.learn_java_with_samples;

public class Test1 {
    
    public Test1() {
        System.out.println("constructor in Test1");
    }
    
    private static String s1 = "static field 1 in Test1";

    static {
        System.out.println("static block 1 in Test1");
    }
    
    {
        System.out.println("non static block 1 in Test1");
    }
    
    private static String s2 = "static field 2 in Test1";

    static {
        System.out.println("static block 2 in Test1");
    }
    
    {
        System.out.println("non static block 2 in Test1");
    }
}

这个类是一个父类,没有被直接引用,但是会被加载并初始化。

package com.learn_java_with_samples;

public class Test2 {
    
    public Test2() {
        System.out.println("constructor in Test2");
    }

    private static String s1 = "static field 1 in Test2";

    static {
        System.out.println("static block 1 in Test2");
    }
    
    {
        System.out.println("non static block 1 in Test2");
    }
    
    private static String s2 = "static field 2 in Test2";

    static {
        System.out.println("static block 2 in Test2");
    }
    
    {
        System.out.println("non static block 2 in Test2");
    }

    public static void test() {
        System.out.println("static method in Test2");
    }
}

这个类被显示初始化了两次。

package com.learn_java_with_samples;

public class Test3 extends Test2 {
    
    public Test3() {
        System.out.println("constructor in Test3");
    }
    
    private static String s1 = "static field 1 in Test3";

    static {
        System.out.println("static block 1 in Test3");
    }
    
    {
        System.out.println("non static block 1 in Test3");
    }
    
    private static String s2 = "static field 2 in Test3";

    static {
        System.out.println("static block 2 in Test3");
    }
    
    {
        System.out.println("non static block 2 in Test3");
    }

    public static void test() {
        System.out.println("static method in Test3");
    }
}

测试类入口。运行这个类时要加上JVM参数 -verbose 以便打印更详细信息。

package com.learn_java_with_samples;

public class Test {
    
    public static void main(String[] args) {
        System.out.println("test start");
        Test3 t1 = new Test3();
        Test3 t2 = new Test3();
        System.out.println("test end");
    }
}

后半段输出节选。

......
[0.076s][info][class,load] sun.security.util.Debug source: jrt:/java.base
[0.077s][info][class,load] com.learn_java_with_samples.Test source: file:/Users/zhangxin/Documents/workspace/learn_java_with_samples/bin/
[0.077s][info][class,load] java.lang.PublicMethods$MethodList source: jrt:/java.base
[0.077s][info][class,load] java.lang.PublicMethods$Key source: jrt:/java.base
[0.077s][info][class,load] java.lang.Void source: jrt:/java.base
test start
[0.078s][info][class,load] com.learn_java_with_samples.Test2 source: file:/Users/zhangxin/Documents/workspace/learn_java_with_samples/bin/
[0.078s][info][class,load] com.learn_java_with_samples.Test3 source: file:/Users/zhangxin/Documents/workspace/learn_java_with_samples/bin/
static block 1 in Test2
static block 2 in Test2
static block 1 in Test3
static block 2 in Test3
non static block 1 in Test2
non static block 2 in Test2
constructor in Test2
non static block 1 in Test3
non static block 2 in Test3
constructor in Test3
non static block 1 in Test2
non static block 2 in Test2
constructor in Test2
non static block 1 in Test3
non static block 2 in Test3
constructor in Test3
test end
[0.078s][info][class,load] jdk.internal.misc.TerminatingThreadLocal$1 source: jrt:/java.base
[0.079s][info][class,load] java.lang.Shutdown source: jrt:/java.base
[0.079s][info][class,load] java.lang.Shutdown$Lock source: jrt:/java.base

由此输出可以看出以下顺序:

  1. Test类被加载,并输出“test start”。
  2. 加载Test2,因为在实例化Test3的时候发现Test2是其父类。
  3. 加载Test3。
  4. 顺序执行父类Test2中的静态块。
  5. 顺序执行子类Test3中的静态块。
  6. 顺序执行父类Test2中的非静态块。
  7. 执行父类Test2中的构造方法。
  8. 顺序执行子类Test3中的非静态块。
  9. 执行子类Test3中的构造方法。
  10. 上述步骤6~9被重新执行一遍,但这次是在实例化t2。
  11. 执行后续语句。

从以上执行顺序可以看出以下几点:

  • Test1虽然也在这个项目中,但没有被用到,所以压根儿没有被加载。
  • 在加载子类的时候,会依次寻找其父类加载。
  • 在初始化子类的时候,会依次寻找其父类,并从其最顶端父类开始依次初始化。
  • 所有静态字段和代码块仅在第一次初始化该类的时候被执行。
  • 非静态字段和代码块在每次初始化时都会被执行。
  • 静态方法仅在被调用时被执行。

本文所有代码在JDK 11上测试通过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值