不加 @override 可能导致静默失败,即误写为新方法而非重写;加上后编译器强制校验签名匹配,及时报错。

重写方法时没加 @Override 会怎样
不会报错,但可能掩盖严重问题。Java 允许你“假装”重写一个方法,比如拼错父类方法名、参数类型写成 int 而不是 Integer、漏掉 throws 声明——这些都会导致你实际定义的是一个全新方法,而非重写。父类逻辑照常执行,子类代码根本不会被调用。
加上 @Override 后,编译器立刻检查:这个方法是否真能在父类(或接口)里找到匹配签名。找不到就直接报错,强迫你面对问题。
- 不加注解 → 静默失败,运行时行为诡异,调试成本高
- 加了注解 → 编译期拦截,错误信息明确指向
method does not override or implement a method from a supertype - IDE(如 IntelliJ)默认在重写时自动插入
@Override,别手抖删掉
@Override 在接口实现中必须加吗
必须加,而且从 Java 6 开始就支持了。很多人以为它只用于继承场景,其实实现接口的抽象方法也属于重写(JVM 层面叫 override),@Override 同样起校验作用。
常见翻车点:接口升级新增 default 方法,你本地没更新接口定义,却在实现类里“重写”了它——没加 @Override 就发现不了签名已不匹配。
立即学习“Java免费学习笔记(深入)”;
- 接口方法名改了?加了新参数?返回类型变了?
@Override会第一时间告诉你 - 用了 Lombok 的
@Data或@Builder?它们生成的toString()、equals()等方法,如果想重写,也得手动加@Override,否则生成的方法和你的冲突
重写时参数/返回类型写错的典型表现
看似写了 @Override,但编译还是过不去,大概率是签名细节对不上。Java 对重写的要求非常严格:方法名、参数数量与类型、返回类型(协变返回除外)、异常声明都得匹配。
例如父类有 protected List<string> getData()</string>,你写成 public ArrayList<string> getData()</string> —— 返回类型虽是子类,但 ArrayList 不是 List 的子类型(而是实现类),这不算协变,编译失败。
- 参数用
intvsInteger:基本类型和包装类互不兼容,不是重写 - 泛型擦除后签名相同,但带泛型声明不同:如
void process(List<string>)</string>和void process(List<object>)</object>,编译器视为两个方法 - 静态方法不能被重写:哪怕加了
@Override,也会报错,因为它是隐藏(hiding),不是重写
为什么有些老项目里完全不用 @Override
因为它们还在用 Java 5。该注解是 Java 5 引入,但直到 Java 6 才支持对接口方法的标记。如果你看到没有 @Override 的代码,先看 source 编译级别;如果是 Java 5 项目,加了反而编译不过。
现在几乎没人再用 Java 5,所以这个“历史原因”只是排查冷门问题时的线索,不是合理跳过的理由。
- Maven 项目检查
<source>1.5</source>配置 - Android 项目注意
compileSdkVersion和sourceCompatibility是否一致 - 加了但编译报错
annotation type not applicable to this kind of declaration?说明 JDK 版本太低,或 IDE 没正确识别语言级别
最常被忽略的一点:@Override 是给编译器和人看的,不是给 JVM 运行时用的。它不改变任何行为,只增加一层契约约束。一旦习惯性加上,你会明显少 debug 半天“为啥我的方法没被调用”。









