1. 主页 > 大智慧

当方法名相同时:重载与重写的实战抉择


一、点咖啡引发的编程思考

那天在星巴克听到这样的对话:
"我要大杯冰美式"
"我要中杯热拿铁"
"我要超大杯去冰摩卡"

突然意识到,这场景不就是活生生的??方法重载??吗?你看,服务员就像Java虚拟机,通过??参数类型(杯型)??和??参数组合(温度+品类)??自动选择对应处理方法。让我们把这个场景写成代码:

java复制
class CoffeeMaker {
    // 重载方法1:基础款
    public void makeCoffee(String size) {
        System.out.println("制作" + size + "标准美式");
    }
    
    // 重载方法2:定制款
    public void makeCoffee(String size, String temperature) {
        System.out.println("制作" + temperature + size + "定制咖啡");
    }
    
    // 重载方法3:顶配款
    public void makeCoffee(String size, String temperature, String type) {
        System.out.println("制作" + temperature + size + type);
    }
}

??开发启示:??

  • 重载就像咖啡店的菜单扩展,保持核心功能(制作咖啡)不变
  • 通过参数差异(数量/类型)自动匹配最佳方案
  • 千万别学某些咖啡师把"大杯"写成"Large"而"中杯"用"Mid",要保持参数类型统一性

二、餐厅点餐系统升级的教训

某连锁餐厅的旧系统是这样的:

java复制
class OrderSystem {
    public void processOrder() {
        // 固定处理堂食订单
    }
}

当需要扩展外卖功能时,菜鸟程序员A直接修改原方法,导致线上订单全部出错。而高手程序员B的选择是:

java复制
class NewOrderSystem extends OrderSystem {
    @Override
    public void processOrder() {
        if(isTakeout) {
            // 处理外卖逻辑
        } else {
            super.processOrder(); // 复用堂食逻辑
        }
    }
}

??这就是方法重写的典型场景:??

  1. 发生在继承关系的父子类之间
  2. 方法名、参数、返回类型完全一致
  3. @Override明确声明覆盖意图
  4. 就像餐厅升级POS系统,保留基础功能,扩展新业务

三、支付系统踩坑实录

最近帮朋友公司排查的诡异Bug:

java复制
class Alipay {
    public void pay(BigDecimal amount) {
        // 支付宝支付逻辑
    }
}

class WechatPay extends Alipay {
    public void pay(Double amount) { // 自以为在重写父类方法
        // 微信支付逻辑
    }
}

当调用new WechatPay().pay(new BigDecimal("100.00"))时,竟然走了父类的支付宝通道!??问题根源:??

  • 参数类型从BigDecimal变成Double,这不叫重写而是重载
  • 正确做法应该保持参数类型一致:
java复制
class WechatPay extends Alipay {
    @Override
    public void pay(BigDecimal amount) { // 真正的重写
        // 微信支付逻辑
    }
}

??避坑指南:??

  • 重写就像银行卡换芯片,卡号(方法签名)不能变,只是内部技术升级
  • 用IDE的@Override注解自动校验是否成功覆盖
  • 涉及钱的计算永远用BigDecimal,别用double埋雷

四、开发场景决策流程图

遇到方法扩展需求时,用这张图快速决策:

 ? ? ? ? ? ? ? ? ? ? ?  ┌───────────┐
 ? ? ? ? ? ? ? ? ? ? ?  │ 需要修改父类行为? │
 ? ? ? ? ? ? ? ? ? ? ?  └─────┬─────┘
 ? ? ? ? ? ? ? ? ? ? ? ? ? ?  ↓
 ? ? ? ? ? ? ? ? ?  ┌─────────┴─────────┐
 ? ? ? ? ? ? ? ? ?  │是 ? ? ? ? ? ? ? ? 否│
 ? ? ? ? ? ? ? ? ?  ↓ ? ? ? ? ? ? ? ? ? ↓
 ? ? ?  ┌─────────────────────┐ ? ┌───────────────┐
 ? ? ?  │使用重写 ? ? ? ? ? ?  │ ? │参数类型/数量不同? │
 ? ? ?  │1.保持方法签名一致 ? ?  │ ? └──────┬──────────┘
 ? ? ?  │2.用@Override注解 ? ? │ ? ? ? ? ? ↓
 ? ? ?  └─────────────────────┘ ? ┌───────┴───────┐
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? │是 ? ? ? ? ? ? 否│
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ↓ ? ? ? ? ? ? ? ↓
 ? ? ? ? ? ? ? ? ? ? ? ┌───────────────────┐ ? ┌────────────┐
 ? ? ? ? ? ? ? ? ? ? ? │使用重载 ? ? ? ? ?  │ ? │新建独立方法  │
 ? ? ? ? ? ? ? ? ? ? ? │1.同方法名 ? ? ? ?  │ ? │避免混淆 ? ?  │
 ? ? ? ? ? ? ? ? ? ? ? │2.参数列表不同 ? ?  │ ? │ ? ? ? ? ?  │
 ? ? ? ? ? ? ? ? ? ? ? └───────────────────┘ ? └────────────┘

五、从Spring框架看实际应用

在SpringBoot中,重写@Bean方法是个典型场景:

java复制
@Configuration
class DatabaseConfig {
    @Bean
    public DataSource dataSource() {
        return new HikariDataSource(); // 默认数据源
    }
}

@Configuration
class CloudDatabaseConfig extends DatabaseConfig {
    @Override
    @Bean
    public DataSource dataSource() { // 重写为云数据库
        return new CloudDataSource();
    }
}

??而MyBatis的XML映射文件解析,则大量使用重载:??

java复制
class SqlSessionTemplate {
    public  T selectOne(String statement) {...}
    public  T selectOne(String statement, Object parameter) {...}
    public  T selectOne(String statement, Object parameter, RowBounds rowBounds) {...}
}

个人编程哲学

做了这么多年Java开发,我有个固执的坚持:??能用重载解决的问题,就不要用重写??。就像手机系统升级,能通过安装新APP(重载)实现的功能,就别轻易刷机(重写系统方法)。特别是在维护祖传代码时,重载的扩展性比重写更安全——毕竟谁也不想成为那个把java.util.DatetoString()方法重写后引发全线崩溃的倒霉蛋。

本文由嘻道妙招独家原创,未经允许,严禁转载