super只能在子类非静态方法或构造器中使用:构造器首行调用super()初始化父类,实例方法中用super.method()调用被重写父类方法;静态上下文、接口体等场景禁止使用。

super调用父类方法时,必须在子类非静态方法或构造器中使用
在Java中,super不是万能的“父类引用”,它只在有明确继承上下文且对象已部分构建时才有效。最常见误用是试图在静态方法里写 super.method() —— 编译直接报错:non-static variable super cannot be referenced from a static context。
真正可用的场景只有两个:
- 在子类构造器第一行调用
super(...)(显式或隐式),用于初始化父类状态 - 在子类实例方法中用
super.methodName()调用被重写的父类方法
注意:不能在静态方法、静态代码块、lambda 表达式或接口默认方法(除非该接口方法被类继承并重写)中使用 super。
重写方法里调用 super.xxx() 与直接写 xxx() 的行为差异
关键区别在于绑定时机:super.xxx() 强制调用父类版本(编译期绑定),而 this.xxx() 或裸调用 xxx() 是运行时动态绑定,可能触发多态调用到当前对象实际类型的重写版本。
立即学习“Java免费学习笔记(深入)”;
比如父类 A 有 log(),子类 B extends A 重写了它,又在 B 中定义新方法 print():
void print() {
super.log(); // 总是执行 A.log()
log(); // 如果 print() 被 C extends B 调用,且 C 也重写了 log(),这里会执行 C.log()
}
这种差异在模板方法模式或回调链中特别关键——漏写 super. 可能导致父类初始化逻辑被跳过。
super() 必须是构造器的第一条语句,且不能和 this() 共存
Java 规定子类构造器要么以 super(...) 开头,要么以 this(...) 开头,二者互斥。如果没写任何显式调用,编译器会自动插入 super()(无参);但一旦父类没有无参构造器,就会编译失败。
典型错误现象:
-
Constructor not defined in parent class(父类只有带参构造器,子类构造器又没显式调用super(x)) -
Call to super must be first statement(在super(...)前写了变量声明或日志打印)
解决办法:检查父类构造器签名,确保子类构造器首行匹配调用;若需复用逻辑,优先提取为工具方法,而非试图绕过这条限制。
接口中无法使用 super 调用默认方法,除非通过类继承链间接触发
Java 接口的默认方法属于“静态可解析”的契约实现,super 关键字在接口中完全不可用。你不能在接口内写 super.toString() 或类似表达式。
但当一个类实现了多个接口,且这些接口有同名默认方法时,编译器会要求该类显式覆写并用 InterfaceName.super.method() 明确选择调用来源:
public class C implements I1, I2 {
public void m() {
I1.super.m(); // 合法:限定接口名 + super
// super.m(); // 编译错误:接口中不允许裸 super
}
}
这个语法是特例,仅适用于接口冲突解决,不适用于普通继承场景,也别和类中的 super 混淆。
最容易被忽略的是:super 在类中永远指向**直接父类**,不会跨级跳转;而接口的 I1.super.m() 是显式路径,和继承层级无关。这两者语义不同,不能互相替代。








