确保多态调用执行子类行为的关键是严格重写:方法签名(名、参数类型及顺序)必须完全一致,返回类型可协变;static、private、final方法无法重写;务必使用@Override注解进行编译期校验。

要让多态调用真正按预期执行子类行为,关键不是“写了同名方法”,而是确保重写严格满足语义匹配——即编译器认可它是重写,而非重载或隐藏。否则看似调用子类方法,实际走的还是父类逻辑,或直接编译报错。
签名必须一字不差:方法名、参数类型与顺序
这是最硬性的门槛。哪怕只是把int换成Integer,或调整参数顺序,Java 就判定为新方法(重载),不参与运行时绑定。
- 父类定义:
public void process(String data, int count) - 子类若写成
public void process(String data, Integer count)→ 编译通过,但不是重写,是重载 - 调用父类引用指向子类对象时,仍会执行父类的
process,除非显式调用重载版本
返回类型允许协变,但不能随意替换
Java 5 起支持协变返回:子类方法可返回父类方法返回类型的子类。这仍是合法重写,且不影响多态分派。
- 父类:
public Animal getPet() - 子类可写:
@Override public Dog getPet()→ ✅ 合法重写,多态有效 - 但若写成:
public Object getPet()→ ❌ 编译失败,返回类型更宽泛不被允许
避开“假重写”陷阱:static、private、final 方法
这些方法从语言机制上就拒绝动态绑定,子类中同名方法不会覆盖,只是独立存在或隐藏。
-
static方法:子类写同名static,属于“隐藏”(hiding),调用取决于引用类型,不是对象类型 -
private方法:子类根本不可见,所谓“重写”实际是全新方法,与父类无绑定关系 -
final方法:编译器直接禁止重写,强行声明会报错
务必加 @Override 注解,让编译器帮你把关
这不是可选项,而是强制建议。它让编译器在编译期检查:该方法是否真能匹配到某个可重写的父类方法。
- 如果父类方法被删了、改名了、参数变了,而子类忘了同步更新,加了
@Override就会立刻报错 - 没有它,你可能长期误以为重写生效,实则一直走父类逻辑,问题隐蔽难排查
- 哪怕父类是接口默认方法或抽象方法,也适用——注解同样起校验作用










