java继承初始化分静态与实例两阶段:静态部分自顶向下仅执行一次,实例部分每次new都按“父进子出”递归执行;字段静态绑定、方法动态绑定,父类构造中调用子类重写方法易致未初始化陷阱。

Java继承体系下的初始化顺序不是按代码书写顺序线性执行,而是由JVM在两个独立阶段分层控制:类加载时的静态初始化、对象创建时的实例初始化。父类与子类的关键差异在于执行时机、触发条件和方向逻辑——静态部分自顶向下只执行一次,实例部分则每次new都走“进入父类→返回子类”的递归路径。
静态初始化:父类先完成,子类后跟进
只要首次主动使用某个类(如 new Child()、访问 Child 的静态字段、调用其静态方法),JVM 就会触发该类及其所有父类的静态初始化。这个过程严格按继承链从上到下推进:
- 先确保父类的全部静态成员已完成初始化:静态变量默认值 → 显式赋值 → 静态块,三者按源码顺序执行
- 父类静态初始化完成后,才开始子类的对应流程
- 整个静态初始化仅发生一次,后续无论创建多少对象或调用多少次静态方法,都不会重复
实例初始化:每次new都走“父进子出”路径
创建子类对象时,实例初始化是逐层展开的递归过程,核心是“父类构造器必须先执行完毕,子类才能继续”:
- 进入 Parent 构造器前:Parent 实例变量设默认值 → 按声明顺序执行显式赋值和实例块 → 执行 Parent 构造函数体
- Parent 构造结束,控制权交还给 Child:Child 实例变量设默认值 → 执行显式赋值和实例块 → 执行 Child 构造函数体
- super() 是隐式或显式的首条语句,它把当前执行流交给父类构造逻辑;没有它,编译直接报错
字段与方法绑定行为不同,容易踩坑
初始化过程中,字段访问和方法调用的绑定机制完全不同:
- 字段访问是静态绑定:看引用的声明类型。比如 Parent p = new Child(); p.i 访问的是 Parent 中定义的 i
- 方法调用是动态绑定:看运行时实际对象类型。父类构造器中调用 print(),即使子类重写了,也会执行子类版本
- 陷阱常见于父类构造器中调用可被重写的方法——此时子类实例变量尚未初始化(仍为默认值),但子类方法已可执行,导致逻辑异常
调试建议:用带标识的日志锚定每个环节
不要依赖记忆或推测顺序,实测最可靠:
- 在每个静态块开头加 “[S] Parent static”、“[S] Child static”
- 在每个实例块开头加 “[I] Parent init”、“[I] Child init”
- 在每个构造函数第一行加 “[C] Parent()”、“[C] Child()”
- 若字段初始化调用了方法(如 String s = load();),也在该方法内加日志,确认执行时机
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











