是的,子类new时父类构造器一定被调用;jvm强制插入super()调用,若父类无无参构造器则需显式调用super(...),且super()必须位于第一行。

子类 new 时父类构造器一定被调用吗
是的,只要父类有可访问的构造器(哪怕没显式写 super()),JVM 就会强制插入对父类构造器的调用。这不是“建议”,是字节码层面的硬性规则——javac 编译时自动补全,不补就编译失败。
常见错误现象:Implicit super constructor XXX() is undefined. Must explicitly invoke another constructor。这说明父类没有无参构造器,而子类又没写 super(...),编译器找不到能插的默认调用点。
- 父类只有带参构造器 → 子类构造器第一行必须显式写
super(…) - 父类有无参构造器(哪怕
private)→ 编译器自动插super(),但若为private,运行时抛IllegalAccessError - 父类构造器抛异常 → 整个子类实例化失败,不会执行子类构造器后续代码
super() 必须放在第一行的原因
这是 JVM 校验规则:对象内存布局在调用任何构造器前已分配(但未初始化),必须由最顶层父类构造器开始逐层“激活”字段和逻辑。如果允许 super() 在中间,意味着子类代码可能读取未初始化的父类字段,破坏内存安全。
使用场景:想在调用父类构造器前做参数预处理?不行。但可以封装成静态方法,再传给 super():
立即学习“Java免费学习笔记(深入)”;
class Child extends Parent {
Child(String raw) {
super(process(raw)); // ✅ 允许:process() 是静态方法,不依赖 this
}
private static String process(String s) { return s.trim(); }
}
容易踩的坑:this.xxx、instanceof、非静态方法调用都不能出现在 super() 前——此时 this 还未完成父类初始化,JVM 直接拒绝。
多层继承中构造器的调用顺序
从 Object 开始,按继承链自顶向下执行:Object → 父类 → 子类。每层只调自己那一级的构造器体,不跳过、不合并、不优化。
性能影响:深度继承链会增加构造开销,尤其当某层构造器做了重操作(如 I/O、反射)。但一般不影响正确性。
- 构造器链是线性的,不是树形:即使子类有多个构造器,每个都只触发一条向上的链
- 字段初始化时机:父类字段在对应父类构造器执行期间赋值;子类字段在子类构造器执行期间赋值(哪怕字段声明在类开头)
- 如果某层构造器被
final修饰,不影响调用顺序,只禁止子类覆盖
父类构造器里调用被子类重写的方法会怎样
会调到子类的重写版本,但此时子类字段还是默认值(null、0、false)。这是最危险的陷阱之一,常导致 NPE 或逻辑错乱。
示例:
class Parent {
String name = "parent";
Parent() {
printName(); // 实际调 Child.printName()
}
void printName() { System.out.println(name); }
}
class Child extends Parent {
String name = "child"; // ✅ 字段已声明,但尚未赋值
Child() { super(); }
@Override void printName() { System.out.println(name); } // 输出 null
}
根本原因:方法调用是动态绑定的,而字段赋值是静态顺序执行的。父类构造器运行时,子类字段还没走到自己的赋值语句。
容易被忽略的地方:这个行为和语言无关(Java/C#/Kotlin 都如此),也不是 bug,是面向对象模型的固有特性。修复方式只有两个:把方法设为 final,或把逻辑移到构造完成后的初始化方法里。










