跳到内容

元数据卡

  • 前置知识:第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——你永远不会后悔。

下一站预告

重写解决了"子类定制父类行为"的问题。但有些时候你要更严格:父类说"这个方法你必须自己实现"——下一站,抽象类和接口。

Built with VitePress | Software Systems Atlas