super()必须写在构造器第一行,因jvm要求父类构造器调用必须是字节码首条指令,否则抛verifyerror;java编译器提前报错“call to super must be first statement”,且this()与super()互斥、均须为首句。

super() 必须写在构造器第一行的原因
因为 Java(以及多数 JVM 语言如 Kotlin)在对象实例化时,会强制要求父类的 super() 调用先于子类字段初始化和任意逻辑执行——这是 JVM 字节码层面的校验规则,不是语法糖或风格约定。
编译器会在字节码中插入 invokespecial 指令调用父类构造器,且该指令必须是构造器方法的第一条可执行指令。否则,JVM 在加载类时直接抛出 VerifyError;Java 编译器则提前拦截,报错 call to super must be first statement in constructor。
不放第一行会触发哪些具体错误
常见错误现象:
- 编译失败,错误信息为:
call to super must be first statement in constructor - 试图在
super()前加日志、变量声明、if判断甚至空行,都会被拒 - Kotlin 中隐式调用
super()同样受约束:若显式写了super(...),它仍必须是第一条语句
注意:this()(调用本类其他构造器)也受同样限制,且与 super() 互斥——二者不能共存,且都必须是首句。
为什么不能延迟或条件化调用 super()
对象初始化顺序是硬性链条:内存分配 → 父类字段默认值 → 父类构造器执行 → 子类字段默认值 → 子类构造器剩余逻辑。如果允许条件调用 super(),JVM 就无法静态确定父类构造器是否一定会被执行,也就无法保证父类状态的完整性。
例如以下写法非法:
class Child extends Parent {
Child(boolean flag) {
if (flag) {
super("yes"); // ❌ 编译不过
} else {
super("no");
}
}
}
解决方式只有两种:
- 把分支逻辑移到父类构造器内部(通过参数传递控制)
- 用静态工厂方法封装判断,再统一调用单入口构造器
容易被忽略的边界情况
很多开发者以为“没写 super() 就没事”,其实不然:
- 若子类构造器没显式写
super()或this(),编译器会自动插入super()(无参),但它依然占据第一行位置——你只是没看见而已 - 父类没有无参构造器时,子类必须显式调用带参的
super(...),否则编译失败,错误信息是:constructor Parent() is undefined - 在匿名内部类或 Lambda 捕获的上下文中 new 对象时,
super()的隐式插入依然生效,别误以为“这里不用管”
最易踩的坑是:以为绕过构造器就能跳过初始化顺序,结果发现字段为 null 或默认值,却去查逻辑 bug,而问题其实在父类构造器里已经依赖了尚未初始化的子类成员(即“过早暴露 this”)。这跟 super() 放哪无关,但常被混淆。










