super()用于调用父类构造器,super.方法名()用于在子类重写方法中显式调用父类被重写的方法,二者本质不同:前者是构造初始化,后者是绕过多态的编译期静态分派。

super() 和 super.方法名() 是两回事
很多人以为 super 只用来调用父类构造器,其实它还能在子类方法里显式调用被重写的父类实例方法。关键区别在于:前者是构造阶段的初始化动作,后者是运行时的方法分派控制。
常见错误是写成 super() 想调父类普通方法,结果编译报错 Constructor call must be first statement in a constructor;或者误以为不写 super. 就能“自动回退”到父类实现——Java 不会这样,重写后子类方法就是唯一入口。
-
super.方法名()必须出现在子类重写方法内部,不能在静态上下文或构造器外独立使用 - 调用的是编译期确定的父类版本,不受多态影响(即绕过动态绑定)
- 如果父类方法是
private或final,super.方法名()会编译失败
什么时候必须用 super.方法名()?
典型场景是模板方法模式或钩子设计:父类定义流程骨架,子类覆盖某步逻辑,但需要在新逻辑中复用父类原始行为。比如日志、权限校验、资源清理等“增强型重写”。
不这样做的话,要么重复父类代码(违反 DRY),要么完全丢弃原有逻辑(破坏契约)。例如 toString() 增强、close() 方法补充清理步骤。
立即学习“Java免费学习笔记(深入)”;
- 父类
process()包含通用预处理和后处理,子类只改中间计算逻辑 → 子类重写时用super.process()拿不到中间结果,得拆成before()/after()钩子再调用 - 想在子类
save()中先执行父类保存逻辑,再发通知 → 直接super.save(); notify(); - 父类方法有副作用(如修改状态字段),而子类需基于该状态做判断 → 必须先触发父类逻辑,再读取状态
容易忽略的访问权限和继承链问题
super.方法名() 能否成功,取决于当前子类**直接继承的父类**是否可访问该方法,跟更上层祖先无关。即使祖父类有 public 方法,若父类把它重写为 private,子类就无法通过 super 触达。
另一个坑是默认访问权限(包级私有):如果父类方法没加修饰符,且子类不在同一包,super.方法名() 编译失败,错误信息是 method is not visible。
- 检查父类方法声明:至少要是
protected或public,且不能被父类自己设为private - 不要依赖 IDE 自动补全的
super.xxx—— 它可能来自间接父类,实际编译不过 - 接口默认方法不能用
super.方法名()调用(得用InterfaceName.super.方法名())
一个简短但真实的例子
假设父类有基础验证逻辑,子类要扩展校验规则但保留原检查:
class Validator {
void validate() {
System.out.println("basic check");
}
}
class EmailValidator extends Validator {
@Override
void validate() {
super.validate(); // ← 关键:复用父类逻辑
System.out.println("email format check");
}
}
如果删掉 super.validate(),输出只剩 “email format check”,业务完整性就断了。这不是语法糖,是明确的控制流选择。
真正复杂的地方在于:当继承链变长、方法签名带泛型、或父类方法抛出受检异常时,super. 的调用必须严格匹配签名,IDE 有时不会立刻标红,但编译器会卡在那一步。


















