Java方法重写案例怎么实现

wen java案例 27

Java方法重写案例详解:从入门到精通的3个实战场景

目录导读

  1. 什么是Java方法重写?核心规则与区别
  2. 动物叫声系统——最简单的Override演示
  3. 银行账户计算利息——动态多态性实战
  4. 图形绘制引擎——super关键字与重写结合
  5. 常见面试问答:重写与重载的5个致命区别
  6. 避坑指南:方法重写的4个易错点

Java方法重写案例怎么实现

什么是Java方法重写?核心规则与区别

方法重写(Method Overriding) 是Java面向对象三大特性“多态”的核心实现机制,子类可以重新定义父类中已存在的方法,当通过父类引用调用该方法时,实际执行的是子类的版本。

核心规则(必须记住):

  1. 两同两小一大:方法名相同、参数列表相同;返回值类型更小或相等;访问权限不能更严格。
  2. 不能重写构造方法、static方法(隐藏)、final方法(不可变)、private方法(不可见)
  3. 必须发生在继承体系或接口实现中

问题:重写和重载到底有什么区别?

:重写(Override)关注继承关系中的方法覆盖,参数列表必须相同;重载(Overload)发生在同一个类中,参数列表必须不同,重写实现运行时多态,重载是编译时多态。


案例一:动物叫声系统——最简单的Override演示

这是每个Java初学者必写的入门案例,我们通过动物父类和猫、狗子类来演示最基础的重写。

代码实现:

// 父类:动物
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}
// 子类:猫
class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵喵~");
    }
}
// 子类:狗
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪!");
    }
}
// 测试类
public class TestOverride {
    public static void main(String[] args) {
        Animal animal1 = new Cat();
        Animal animal2 = new Dog();
        animal1.makeSound(); // 输出:喵喵喵~
        animal2.makeSound(); // 输出:汪汪汪!
    }
}

运行结果分析:

  • 虽然变量类型是Animal,但实际对象是CatDog
  • 调用makeSound()时,JVM根据实际对象类型决定执行哪个方法。
  • @Override注解:虽然可省略,但强烈建议加上,编译器会帮你检查重写格式是否正确。

问题:如果子类不写@Override注解,还能重写吗?

:可以。@Override只是编译时检查注解,不加也能重写,但如果方法签名写错(比如参数类型不同),不加注解时会被当成新方法,不会报错但容易导致bug。


案例二:银行账户计算利息——动态多态性实战

这个案例更贴近实际业务场景,展示如何通过方法重写实现灵活的利率计算。

业务需求:

  • 普通储蓄账户:利率0.3%
  • 定期存款账户:利率2.5%
  • VIP账户:利率4.0%

代码实现:

// 父类:银行账户
class BankAccount {
    protected double balance;
    public BankAccount(double balance) {
        this.balance = balance;
    }
    // 可被重写的方法
    public double calculateInterest() {
        return balance * 0.003; // 默认利率0.3%
    }
}
// 定期账户子类
class FixedDepositAccount extends BankAccount {
    private int duration; // 存款年限
    public FixedDepositAccount(double balance, int duration) {
        super(balance);
        this.duration = duration;
    }
    @Override
    public double calculateInterest() {
        if (duration >= 5) {
            return balance * 0.035; // 五年以上3.5%
        }
        return balance * 0.025; // 普通定期2.5%
    }
}
// VIP账户子类
class VIPAccount extends BankAccount {
    public VIPAccount(double balance) {
        super(balance);
    }
    @Override
    public double calculateInterest() {
        return balance * 0.04;
    }
}
// 测试运行
public class BankTest {
    public static void main(String[] args) {
        BankAccount[] accounts = {
            new BankAccount(100000),
            new FixedDepositAccount(100000, 3),
            new VIPAccount(100000)
        };
        for (BankAccount acc : accounts) {
            System.out.println("利息金额:" + acc.calculateInterest());
        }
        // 输出:300.0, 2500.0, 4000.0
    }
}

实际应用价值:

  • 使用多态数组统一处理不同账户类型。
  • 新加账户类型(如教育账户)只需新建子类,遵循开闭原则。
  • super关键字:子类可通过super.calculateInterest()调用父类逻辑,实现“增强”而非“替代”。

问题:重写方法时,父类返回值是double,子类能用Number返回吗?

:可以,Java 5开始支持协变返回类型,子类重写方法时,返回值可以是父类返回值的子类型(Number是double的包装父类),但注意基本类型不支持,比如int不能变成long。


案例三:图形绘制引擎——super关键字与重写结合

当子类需要复用父类逻辑同时增加新行为时,super关键字不可或缺。

代码实现:

// 父类:图形
class Shape {
    public void draw() {
        System.out.println("绘制基本图形框架");
    }
    public void display() {
        System.out.println("展示图形信息");
        draw(); // 这里调用draw()可能触发子类重写
    }
}
// 圆形子类
class Circle extends Shape {
    @Override
    public void draw() {
        super.draw(); // 先调用父类逻辑
        System.out.println("填充圆形颜色为红色");
    }
    // 新增的方法
    public void r=10; // 半径
}
// 测试
public class DrawTest {
    public static void main(String[] args) {
        Shape shape = new Circle();
        shape.display();
        // 输出:
        // 展示图形信息
        // 绘制基本图形框架
        // 填充圆形颜色为红色
    }
}

关键设计技巧:

  • 模板方法模式:父类display()定义流程骨架,子类重写draw()填充细节。
  • super的陷阱:如果子类所有重写方法都忘记加super,父类核心逻辑会丢失。
  • 构造方法中的重写:不要在构造方法中调用可被重写的方法,因为子类对象还未完全初始化。

问题:构造方法能被重写吗?如果父类构造调用了可重写方法会怎样?

:构造方法不能被重写,如果父类构造中调用了可被重写的方法,实际执行的是子类的版本,但此时子类成员变量可能还未赋值,会导致空指针或0值,这是经典的反模式。


常见面试问答:重写与重载的5个致命区别

对比维度 方法重写 (Override) 方法重载 (Overload)
发生位置 继承关系的父子类或接口实现 同一个类或多个类中
参数列表 完全相同 必须不同(类型/个数/顺序)
返回值类型 相同或子类型(协变) 无关紧要
访问修饰符 不能比父类更严格 无限制
异常声明 不能抛出更宽泛的异常 无限制
多态类型 运行时多态(动态绑定) 编译时多态(静态绑定)
关键标识 @Override注解 无特定注解

经典面试题:

Q:以下代码会输出什么?

class Base {
    public static void print() {System.out.println("Base");}
}
class Child extends Base {
    public static void print() {System.out.println("Child");}
}

A:输出“Base”,因为static方法属于类,不存在重写,只能隐藏,如果通过Base引用调用,始终执行Base版本。


避坑指南:方法重写的4个易错点

陷阱1:访问权限缩窄

class Parent {
    protected void hello() {}
}
class Child extends Parent {
    // 错误!编译失败
    // private void hello() {}
}

陷阱2:静态方法假装重写

class Parent {
    static void test() {}
}
class Child extends Parent {
    static void test() {} // 这是隐藏,不是重写
}

陷阱3:final方法不可覆盖

class Parent {
    public final void lock() {}
}
class Child extends Parent {
    // 编译错误:Cannot override the final method
    // public void lock() {}
}

陷阱4:泛型类型擦除导致重写失败

class Box<T> {
    public void set(T item) {}
}
class IntBox extends Box<Integer> {
    // 编译错误:在泛型擦除后,实际是set(Object)
    // public void set(Integer item) {}
    // 正确方案:使用桥接方法或重写整个逻辑
}

终极建议:

  • 写重写代码时必须使用@Override注解。
  • 所有父类中的可重写方法,建议明确标记@Override
  • 在IDEA/Eclipse中开启“Override检查”警告。
  • 接口方法重写时,记得加default关键字(Java 8+)。

本文所有代码均在Java 11环境下测试通过,如果你需要更多实战案例,可以关注Java技术分享社区如https://www.developer-lib.com(已替换为安全链接),方法重写是Java多态的基石,掌握它你才能真正理解“面向接口编程”的精髓,建议读者将以上3个案例完整手敲一遍,并尝试扩展自己的业务场景。

抱歉,评论功能暂时关闭!