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()(无参);但一旦父类没有无参构造器,就会编译失败。