方法重载与重写

一、方法重载(Overloading)深度解析

1.1 基础语法规范

public class Calculator {
    // 整型相加
    public int add(int a, int b) {
        return a + b;
    }
  
    // 浮点型相加(参数类型不同)
    public double add(double a, double b) {
        return a + b;
    }
  
    // 三数相加(参数数量不同)
    public int add(int a, int b, int c) {
        return a + b + c;
    }
  
    // 编译错误!仅返回类型不同不能构成重载
    // public double add(int a, int b) { return a + b; }
}

1.2 重载决策的三个维度

维度示例编译器优先级
精确匹配add(2,3) → int版本★★★★★★
自动类型转换add(2.5,3) → double★★★☆☆☆
可变参数add(2,3,4,5) → 变参★☆☆☆☆☆

方法调用

存在精确匹配?

选择精确匹配

存在类型转换路径?

选择最小转换代价

检查变参方法?


二、方法重写(Overriding)核心原理

2.1 重写规范的"两同两小一法则"

class Animal {
    public Number move(int meters) throws IOException {
        System.out.println("Animal moving");
        return meters * 0.8;
    }
}
​
class Dog extends Animal {
    @Override
    public Integer move(int distance) throws FileNotFoundException {
        System.out.println("Dog running");
        return distance * 2;
    }
}

规则分解表

规则项父类方法子类方法
返回值类型NumberInteger(协变返回类型)
异常范围IOExceptionFileNotFoundException(缩小子类异常)
访问权限publicpublic(保持或更开放)
方法签名move(int)move(int)(严格一致)

2.2 JVM方法表实现机制


三、本质区别深度对比

对比维度方法重载(Overloading)方法重写(Overriding)
发生层级同一类或父子类继承关系的父子类之间
参数列表必须不同必须完全相同
返回类型可以不同协变返回类型
访问修饰符任意不能更严格
异常声明无限制不能扩展父类异常范围
编译阶段静态绑定(编译时多态)动态绑定(运行时多态)
JVM处理方法签名唯一性虚方法表调度

Animal+eat()Dog+eat()+eat(foodType)+eat(foodType, quantity)


四、工程实践中的典型应用

4.1 重载实践场景

框架开发之Log工具类

public class Logger {
    public static void log(String message) {
        System.out.println("[INFO] " + message);
    }
  
    public static void log(String message, Throwable error) {
        System.out.println("[ERROR] " + message);
        error.printStackTrace();
    }
  
    public static void log(String format, Object... args) {
        System.out.printf("[DEBUG] " + format + "\n", args);
    }
}

4.2 重写实践场景

Spring框架的模板模式

public abstract class JdbcTemplate {
    // 不可变的算法骨架
    public final List<?> query(String sql) {
        // 获取连接
        Connection conn = getConnection();
        // 交给子类实现结果处理
        return processResult(conn.execute(sql));
    }
  
    protected abstract List<?> processResult(ResultSet rs);
}
​
public class UserDao extends JdbcTemplate {
    @Override
    protected List<User> processResult(ResultSet rs) {
        // 具体的结果处理逻辑
    }
}

五、高级技术内幕揭秘

5.1 Java语法糖与重载陷阱

public class VarArgsTrap {
    void process(int... nums) {}
    void process(int num1, int num2) {}
  
    public static void main(String[] args) {
        VarArgsTrap obj = new VarArgsTrap();
        obj.process(1,2);  // 优先匹配确定参数方法
        obj.process(1);    // 只能调用变参版本
    }
}

5.2 桥接方法与泛型重写

interface Processor<T> {
    void process(T obj);
}
​
class StringProcessor implements Processor<String> {
    // 编译器生成桥接方法:
    // public void process(Object s){ process((String)s); }
    @Override
    public void process(String s) {
        System.out.println("Processing: " + s);
    }
}

六、常见踩坑与解决方案指南

6.1 重载参数优先级谜题

public class Confusion {
    void exec(Object obj) { System.out.println("Object"); }
    void exec(String str) { System.out.println("String"); }
  
    public static void main(String[] args) {
        new Confusion().exec(null);  // 输出String而非Object!
    }
}

回避策略

  • 使用@Param注解显式限定

  • 避免重载参数类型存在继承关系


6.2 构造器重写迷思


特殊方法不能被重写

父类构造器

子类构造器必须直接声明

正确写法

class Parent {
    Parent(int value) {}
}
​
class Child extends Parent {
    Child() {
        super(0);  // 必须显式调用父类构造器
    }
}

性能优化建议: ✅ 慎用自动装箱触发意外重载 ✅ 核心方法避免过多重载版本(建议不超过5个) ✅ 用@Override注解严格校验重写操作 ✅ IDE设置为自动检测重载冲突


扩展思考

  1. Java 11的var关键字对重载机制的影响?

  2. 接口默认方法与类方法的重载优先级

  3. 记录类(Record)在方法重载中的特殊表现


实战演练

// 方法签名字符串生成实验
public class SignatureTest {
    public static void main(String[] args) throws Exception {
        Method method = SignatureTest.class.getMethod("test", int.class);
        System.out.println("方法签名:" + method.toString());  // 显示完整签名
    }
  
    public static void test(int param) {}
}

终极对比表

┌───────────────┬─────────────────────┬──────────────────────┐
│   维度        │ 静态多态(重载)     │ 动态多态(重写)      │
├───────────────┼─────────────────────┼──────────────────────┤
│ 绑定时机      │ 编译时               │ 运行时               │
│ 对象类型      │ 无关                 │ 关键依赖             │
│ 性能消耗      │ 无额外开销           │ vtable查询开销       │
│ 设计目标      │ 功能多样性           │ 行为扩展性           │
└───────────────┴─────────────────────┴──────────────────────┘

💡 深度讨论:为何Java不将this.getClass()信息纳入重载决策机制? 📚 推荐阅读

  • 《Java编程思想》第8章"多态"

  • JLS规范 §8.4.9 Overloading

  • 《深入理解Java虚拟机》方法调用章节

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值