Java 重写与重载:一篇讲透两个易混淆的概念

95 阅读4分钟

🤔 从一个真实场景说起

你是否遇到过这样的困惑?

  • 写了一个 Animal 类,里面有个 makeSound() 方法,想让 Dog 类和 Cat 类发出不同的叫声
  • 设计 Calculator 类时,想让 add() 方法既能算两个整数相加,又能算两个小数相加 这两个场景,其实分别对应了Java中的 重写(Override) 和 重载(Overload) 。今天,我们就来彻底搞懂这两个概念!

🔄 重写(Override):子类对父类的"定制化改造"

重写就像子类继承父类后,对父类的方法进行"个性化定制"——方法名不变,但实现细节根据子类特点进行调整。

重写的四大核心特征

    方法签名完全一致 :方法名、参数列表必须完全相同(返回值可以是父类返回值的子类,称为"协变返回类型")
    访问权限不能更严格 :父类是 public ,子类不能是 private 或 protected
    父类方法不能是final或static :final方法不可修改,static方法属于类而非实例
    @Override注解 :虽然不是必须,但加上能在编译时检查是否符合重写规则

重写的生动示例

class Animal {
    // 父类方法
    public void makeSound() {
        System.out.println("动物发出叫声");
    }
}

class Dog extends Animal {
    // 重写父类方法
    @Override
    public void makeSound() {
        System.out.println("狗汪汪叫");
    }
}

class Cat extends Animal {
    // 重写父类方法
    @Override
    public void makeSound() {
        System.out.println("猫喵喵叫");
    }
}

// 测试代码
public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal dog = new Dog();  // 多态
        Animal cat = new Cat();  // 多态

        animal.makeSound();  // 输出: 动物发出叫声
        dog.makeSound();     // 输出: 狗汪汪叫
        cat.makeSound();     // 输出: 猫喵喵叫
    }
}

💡 关键:当使用多态(父类引用指向子类对象)时,调用的是子类重写后的方法,这体现了Java的动态绑定特性。

⚡ 重载(Overload):同一类中的"方法多面手"

重载就像一个方法有多个"分身"——方法名相同,但能处理不同类型或数量的参数,就像瑞士军刀的不同功能。

重载的三大核心特征

    方法名必须相同 :这是重载的基本标识
    参数列表必须不同 :参数个数、类型或顺序至少有一项不同
    返回值类型可以不同 :但仅靠返回值类型不同不能构成重载

重载的实用示例

class Calculator {
    // 两个整数相加
    public int add(int a, int b) {
        return a + b;
    }
    
    // 三个整数相加(参数个数不同)
    public int add(int a, int b, int c) {
        return a + b + c;
    }
    
    // 两个小数相加(参数类型不同)
    public double add(double a, double b) {
        return a + b;
    }
    
    // 先int后String(参数顺序不同)
    public void printResult(int num, String prefix) {
        System.out.println(prefix + num);
    }
    
    // 先String后int(参数顺序不同)
    public void printResult(String prefix, int num) {
        System.out.println(prefix + num);
    }
}

// 测试代码
public class Test {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        
        System.out.println(calc.add(12));          // 调
        用int+int
        System.out.println(calc.add(123));       // 调
        用int+int+int
        System.out.println(calc.add(1.52.5));      // 调
        用double+double
        
        calc.printResult(100"结果:");             // 调用
        int,String
        calc.printResult("分数:"95);             // 调用
        String,int
    }
}

💡 关键:Java编译器会根据参数的类型、个数和顺序来确定具体调用哪个重载方法,这发生在编译期。

📊 重写与重载的核心区别

维度 重写(Override) 重载(Overload) 发生位置 子类与父类之间 同一个类中 方法名 必须相同 必须相同 参数列表 必须相同 必须不同(个数/类型/顺序) 返回值 必须相同(或协变子类) 可以不同 权限修饰符 不能比父类更严格 无限制 绑定时期 运行时(动态绑定) 编译时(静态绑定) 目的 改写父类行为 处理不同参数情况

🧠 记忆口诀: 重写是"父子同名同参不同实现",重载是"同类同名不同参"

⚠️ 常见误区与注意事项

    重写时参数列表必须完全一致 :哪怕只是参数名称不同,也不算重写(编译会报错)
    重载不能仅靠返回值区分 :如果两个方法只有返回值不同,会导致编译错误
    private方法不能被重写 :因为private方法对子类不可见
    构造方法不能被重写 :但可以被重载(这就是为什么一个类可以有多个构造方法)
    静态方法不存在重写 :静态方法属于类,调用时由引用类型决定,而非对象类型

🚀 实际应用场景

  • 重写 :常用于实现多态,比如在框架中扩展基类功能(如Spring中的各种模板方法)
  • 重载 :常用于提供灵活的API,比如 StringBuilder.append() 方法支持多种数据类型

💡 总结

重写和重载是Java面向对象编程的核心概念,虽然容易混淆,但只要记住:

  • 重写是子类对父类方法的"定制化改造",发生在运行时
  • 重载是同一类中方法的"多面手",发生在编译时 掌握这两个概念,能让你的代码更加灵活、可扩展。下次写代码时,不妨想想:这个场景该用重写还是重载?

🔖 收藏本文,下次遇到重写与重载的困惑时,随时查看!