讲讲类的实例化顺序¶
结论¶
以 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();
}
}
输出:
关键点¶
- 静态部分只执行一次:类加载时,且先父后子。
- 实例部分每次 new 都执行:先父后子。
- 实例变量和实例代码块按源码顺序执行,合并到构造函数中。
- 构造函数最后执行。
为什么这样设计¶
- 子类构造器第一行默认
super(),所以父类先初始化。 - 静态部分在类加载阶段,只执行一次。
高频追问
- 如果子类重写了父类方法,构造函数里调用被重写方法,会调到子类的版本(多态),但此时子类字段可能还没初始化。
- 这就是"不要在构造函数里调用可重写方法"的原因。