Java方法重写:子类覆盖父类方法,实现多态基础

方法重写:子类如何“修改”父类的方法?

在Java中,当我们创建子类继承父类时,有时需要对父类的方法进行“个性化修改”——这就是方法重写(Override)。简单来说,方法重写就是子类根据自身需求,在保留方法声明(名称、参数等)不变的前提下,重新编写方法的具体实现。

为什么需要方法重写?

想象一下:如果父类定义了一个通用的“动物吃饭”方法,子类“狗”和“猫”虽然都是动物,但吃饭的行为不同(狗吃骨头,猫吃鱼)。直接使用父类方法显然不符合子类的需求,而方法重写能让子类灵活地修改这个方法的内容,同时保持方法声明的一致性。

方法重写的“规则”(必须满足的条件)

要正确实现方法重写,需要满足以下规则(缺一不可):

  1. 方法名和参数列表必须完全相同
    子类方法的名称、参数的数量、类型、顺序必须与父类方法一致。例如:父类 eat() 方法的参数是 (),子类重写时也必须是 eat()

  2. 返回值类型“协变”
    子类方法的返回值类型可以是父类方法返回值类型本身,或者是它的“子类类型”(例如:父类返回 Object,子类返回 String;父类返回 Animal,子类返回 Dog)。

  3. 访问权限不能更严格
    子类方法的访问权限必须大于或等于父类方法。例如:父类方法是 public,子类可以是 publicprotected;父类是 protected,子类不能写成 private(权限缩小会导致编译错误)。

  4. 异常处理更宽松
    子类方法抛出的异常必须是父类方法抛出异常的“子类”或更少异常(不能抛出比父类更多或更宽泛的异常)。

举个例子:动物吃饭的重写

我们用代码直观感受方法重写:

// 父类:动物类
class Animal {
    // 父类的方法:吃饭(通用实现)
    public void eat() {
        System.out.println("动物吃饭");
    }
}

// 子类:狗类(继承Animal)
class Dog extends Animal {
    // 重写父类的eat()方法
    @Override
    public void eat() {
        System.out.println("狗吃骨头!");
    }
}

// 子类:猫类(继承Animal)
class Cat extends Animal {
    // 重写父类的eat()方法
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
}

// 测试类
public class TestOverride {
    public static void main(String[] args) {
        Dog dog = new Dog();
        Cat cat = new Cat();

        dog.eat(); // 输出:狗吃骨头!
        cat.eat(); // 输出:猫吃鱼!
    }
}

关键点@Override 注解是可选的,但加上后编译器会帮我们检查是否真的满足重写规则(例如方法名拼写错误会报错),建议养成习惯。

方法重写与“多态”的关系

方法重写是多态(Polymorphism)的核心基础,尤其是“运行时多态”(动态绑定)。当父类引用指向子类对象时,调用重写的方法会自动执行子类的实现。

// 父类引用指向子类对象
Animal a = new Dog(); 
a.eat(); // 输出:狗吃骨头!(执行子类的重写方法)

a = new Cat();
a.eat(); // 输出:猫吃鱼!(执行子类的重写方法)

这里 aAnimal 类型的引用,但实际指向 DogCat 对象,调用 eat() 时会根据对象的实际类型(子类)执行对应的方法——这就是“多态”的体现。

方法重写 vs 方法重载(别搞混!)

初学者容易混淆方法重写方法重载(Overload),两者的区别如下:

对比项 方法重写(Override) 方法重载(Overload)
发生场景 子类对父类的方法进行修改 同一类中方法名相同,参数不同
核心目标 扩展/修改父类行为,实现多态 同一功能的不同参数版本(参数列表不同)
规则 名称、参数列表、返回值需一致 名称相同,参数列表(数量/类型/顺序)不同

总结

方法重写是Java中实现代码复用和扩展的重要机制,它让子类既能继承父类的“框架”,又能根据自身需求修改“细节”。同时,方法重写是多态的核心基础——通过父类引用指向子类对象,程序能在运行时自动选择正确的方法实现,大幅提升代码的灵活性和可扩展性。

小练习:尝试定义一个 Bird 类继承 Animal,重写 eat() 方法输出“鸟吃虫子”,然后用多态方式测试!

小夜