子类重写方法必须严格满足签名一致:方法名、参数类型(含顺序和个数)、返回类型(或其协变子类型)三者完全匹配;private、static、final 方法不可重写;应始终使用@override注解校验。

子类重写方法时必须满足签名一致
方法重写不是“随便换个实现”,而是严格绑定父类方法签名的替换行为。只要 method name、parameter types(含顺序和个数)、return type(或其协变子类型)三者完全匹配,JVM 才会在运行时将调用路由到子类版本。
常见错误现象:父类是 void process(List<string> data)</string>,子类写成 void process(ArrayList<string> data)</string> —— 这是重载,不是重写;编译不报错,但多态调用永远进不去这个方法。
- 参数类型必须逐个相同(泛型擦除后原始类型也要一致)
- 返回值允许协变(如父类返回
Animal,子类可返回Dog),但基本类型(int→long)或包装类(Integer→Number)不行 - 访问修饰符不能更严格(
protected父类方法,子类不能用private或默认权限)
@Override 注解不是装饰,是校验开关
不加 @Override,JVM 仍按规则执行重写逻辑;但一旦漏加,拼错方法名、参数类型写错、父类方法被删掉,编译器就无法提醒你——你以为在重写,实际只是新增了一个同名方法。
典型反例:public void save(User user) 在父类中,子类误写为 public void save(Admin user)(Admin 是 User 子类),没加 @Override 就不会报错,但 Animal a = new Dog(); a.save(new User()) 调用的仍是父类方法。
- IDE 默认提示添加,建议始终开启并保留
- Java 5 起支持,Java 8 后也适用于实现接口默认方法
- 编译报错
Method does not override method from its superclass时,优先检查签名是否真的一致(尤其注意泛型、数组符号、自动装箱差异)
重写后如何复用父类逻辑
子类要扩展而非完全抛弃父类行为时,用 super.methodName() 显式调用父类实现。这不是语法糖,而是唯一能绕过动态绑定、强制走父类路径的方式。
常见错误现象:在子类 toString() 中忘记调用 super.toString(),导致父类字段信息丢失;或在 close() 方法中漏掉 super.close(),引发资源未释放。
-
super只能在非static、非private、非final的实例方法中使用 - 调用位置无硬性限制,但通常放在开头(前置增强)或结尾(后置清理)
- 若父类方法抛出受检异常,子类重写时仍需声明相同或子类异常,否则编译失败
哪些方法根本不能被重写
不是所有父类方法都开放重写权限。以下三类方法在语法层面就被 JVM 拦截:
-
private方法:子类不可见,所谓“重写”只是定义了新方法 -
static方法:属于类,不是对象,子类同名方法是“隐藏”(hiding),调用取决于引用类型而非实际类型 -
final方法:编译期直接拒绝,报错Cannot override the final method from XXX
最容易被忽略的是 static 方法——写一个同名 static 方法看似“覆盖”,但 Animal a = new Dog(); a.staticMethod() 实际调用的是 Animal.staticMethod(),因为静态绑定发生在编译期。










