跳转至

讲讲类的实例化顺序

结论

new Son() 为例,执行顺序:

1. 父类静态变量 / 静态代码块     (只执行一次,类加载时)
2. 子类静态变量 / 静态代码块     (只执行一次,类加载时)
3. 父类实例变量 / 实例代码块
4. 父类构造函数
5. 子类实例变量 / 实例代码块
6. 子类构造函数

代码验证

class Parent {
    static int pStatic = 1;
    int pInstance = 2;

    static { System.out.println("父类静态块"); }
    { System.out.println("父类实例块"); }

    Parent() { System.out.println("父类构造器"); }
}

class Son extends Parent {
    static int sStatic = 3;
    int sInstance = 4;

    static { System.out.println("子类静态块"); }
    { System.out.println("子类实例块"); }

    Son() { System.out.println("子类构造器"); }
}

public class Test {
    public static void main(String[] args) {
        new Son();
        System.out.println("---");
        new Son();
    }
}

输出:

父类静态块
子类静态块
父类实例块
父类构造器
子类实例块
子类构造器
---
父类实例块
父类构造器
子类实例块
子类构造器

关键点

  1. 静态部分只执行一次:类加载时,且先父后子。
  2. 实例部分每次 new 都执行:先父后子。
  3. 实例变量和实例代码块按源码顺序执行,合并到构造函数中。
  4. 构造函数最后执行

为什么这样设计

  • 子类构造器第一行默认 super(),所以父类先初始化。
  • 静态部分在类加载阶段,只执行一次。

高频追问

  • 如果子类重写了父类方法,构造函数里调用被重写方法,会调到子类的版本(多态),但此时子类字段可能还没初始化。
  • 这就是"不要在构造函数里调用可重写方法"的原因。