元数据卡
- 前置知识:第8章(上)继承、extends
- 预计时间:15 分钟
- 阅读模式:概念理解 + 动手
- 完成标志:能正确使用
@Override和安全检查,理解super的两种用途
你的进度
写完三个子类之后,你发现一个问题:有时候你明明想"重写"父类的方法,但手一抖把方法名拼错了,编译器不报错,程序运行结果却不对。
java
public class Horse extends MessageSender {
// 想重写 send(),但不小心写成了 snd()
public void snd() {
System.out.println("策马奔腾!");
}
}
// 调用时:
new Horse("敌军来袭", "张三").send(); // 咦?怎么只打印了父类的消息?编译器不会告诉你,它觉得你是想增加一个叫 snd 的新方法。Bug 就这样静悄悄地潜伏了。
你的任务:如何让编译器帮你抓住这种笔误?只用加一行代码。
第一幕:@Override——编译器的安全网
java
// Horse.java — 加上 @Override
public class Horse extends MessageSender {
private String riderName;
public Horse(String message, String riderName) {
super(message);
this.riderName = riderName;
}
@Override
public void send() {
super.send();
System.out.println("骑士 " + riderName + " 策马奔腾!");
}
}@Override 不是功能性的,它是编译器的安全检查。你告诉编译器"我要重写父类的一个方法"。如果父类没有同名同参数的方法(你拼错了方法名,或者参数类型写错了),编译器会报错,而不是悄悄地创建一个新方法。
java
// 编译器会报错!
@Override
public void snd() { // 报错:Horse 中没有方法覆盖父类的方法
// ...
}语言:Java 17+ 你试试:去掉 @Override,再试试把 String 参数改成 int——看看 @Override 为什么能帮我们发现错误。
第二幕:super 的两种用途
super 关键字有两个明确的用途:
用途一:调用父类构造器
必须在子类构造方法的第一行:
java
public Horse(String message, String riderName) {
super(message); // 调用父类 MessageSender 的构造器
this.riderName = riderName;
}如果漏写,编译器会隐式插入 super()。但如果父类没有无参构造器,就编译报错。
用途二:调用被重写的父类方法
java
@Override
public void send() {
super.send(); // 先执行父类 MessageSender 的 send()
System.out.println("骑士 " + riderName + " 策马奔腾!");
}没有 super.send(),子类的 send() 就完全覆盖了父类版本。
第三幕:方法重写 vs 方法重载——一字之差
| 特性 | 方法重写 (Override) | 方法重载 (Overload) |
|---|---|---|
| 什么时候 | 子类重新定义父类方法 | 同一个类里多个同名方法 |
| 参数列表 | 完全相同 | 必须不同 |
| 关键字 | @Override | 无关键字 |
| 绑定时间 | 运行时(动态绑定) | 编译时 |
java
public class Horse extends MessageSender {
@Override
public void send() { ... } // 重写——参数、方法名、返回类型完全一样
public void send(String priority) { ... } // 这是重载——参数不同,但不是重写!
}一个隐蔽的坑:你想重写,但方法签名写错了(比如少了一个参数)。没有 @Override,编译器不会报错——它认为你在定义新方法。所以永远加 @Override。
旅人笔记
@Override是安全网,帮你抓住笔误。super两种用途:调父类构造器、调被重写的父类方法。 重写靠@Override,重载靠参数不同。 永远加@Override——你永远不会后悔。
→ 下一站预告
重写解决了"子类定制父类行为"的问题。但有些时候你要更严格:父类说"这个方法你必须自己实现"——下一站,抽象类和接口。