Java程序中类的初始化顺序

910 阅读2分钟

注:本专栏文章均为本人原创,未经本人授权请勿私自转载,谢谢。

一、类的初始化过程

  1. 一个类要创建实例需要先加载并初始化该类,main方法所在的类需要先加载和初始化。
  2. 一个子类要初始化需要先初始化父类
  3. 一个类的初始化就是执行()方法:
  • ()方法由静态类变量显式赋值代码和静态代码块组成
  • 静态类变量显式赋值代码和静态代码块按照代码的书写顺序依次执行
  • ()方法只执行一次

二、实例的初始化过程

  1. 一个实例的初始化就是执行()方法
  • ()方法可能重载有多个,有几个构造器就有几个()方法
  • ()方法由非静态实例变量显式赋值代码、非静态代码块、以及对应构造器代码组成
  • 非静态实例变量显式赋值代码和非静态代码块按照代码的书写顺序依次执行,对应构造器代码组成最后执行
  • 每次创建实例对象,调用对应构造器,执行的就是对应的()方法
  • ()方法的首行是super()或super(实参列表),即对应父类的()方法

三、总初始化流程

  1. 父类的静态变量 -> 2. 父类的静态代码块 -> 3. 子类的静态变量 -> 4. 子类的静态代码块 -> 5. 父类的非静态变量 -> 6. 父类的非静态代码块 -> 7. 父类的构造函数 -> 8. 子类的非静态变量 -> 9. 子类的非静态代码块 -> 10. 子类的构造函数

例题:请写出以下程序的输出:

static class Father {
    private int i = test();
    private static int j = method();
​
    static {
        System.out.print("(1)");
    }
​
    Father() {
        System.out.print("(2)");
    }
​
    {
        System.out.print("(3)");
    }
​
    public int test() {
        System.out.print("(4)");
        return 1;
    }
​
    public static int method() {
        System.out.print("(5)");
        return 1;
    }
}
​
static class Son extends Father {
    private int i = test();
    private static int j = method();
​
    static {
        System.out.print("(6)");
    }
​
    Son() {
        System.out.print("(7)");
    }
​
    {
        System.out.print("(8)");
    }
​
    public int test() {
        System.out.print("(9)");
        return 1;
    }
​
    public static int method() {
        System.out.print("(10)");
        return 1;
    }
}
​
public static void main(String[] args) {
    Son s1 = new Son();
    System.out.println();
    Son s2 = new Son();
}

题解

  1. 首先执行类的初始化,先初始化父类,由于静态类变量显式赋值代码在静态代码之前,所以先执行静态类变量显式赋值代码(5),然后执行(1);初始化子类同理,依次执行(10)(6)。
  2. 然后执行实例的初始化,先初始化父类,由非静态实例变量显式赋值代码在非静态代码块,所以先执行非静态实例变量显式赋值代码,test()方法(9),然后执行(3),最后执行构造器代码(2);初始化子类同理,依次执行(9)(8)(7)。
  3. 由于实例化了两个对象,第二步实际上被执行了两次,所以最终执行的顺序为:(5)(1)(10)(6) -> (9)(3)(2)(9)(8)(7) -> (9)(3)(2)(9)(8)(7)