杰瑞科技汇

重写与重载,到底有啥区别?

  • 方法重载:就像一个厨房里可以有多个功能相似但参数不同的“榨汁机”,你可以放苹果(juice(Apple a)),也可以放橙子(juice(Orange o)),还可以放一杯现成的果汁让它混合(juice(Juice j)),这些方法都叫“榨汁”,但能处理的东西不同。
  • 方法重写:就像一个家族里,父亲会开车,儿子也学会了开车,儿子开车的方式(方法实现)和父亲可能不同(比如儿子开得更快,或者用的是自动驾驶),但“开车”这个行为(方法名)和它能完成的事情(返回类型、参数列表)是一样的,儿子用自己的方式覆盖了父亲的方式。

方法重载

定义

同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同(参数个数、参数类型或参数顺序不同)即可。

重写与重载,到底有啥区别?-图1
(图片来源网络,侵删)

核心规则

  • 方法名必须相同
  • 参数列表必须不同,这是区分重载方法的关键。
    • 参数个数不同。
    • 参数类型不同。
    • 参数顺序不同(method(int, String)method(String, int) 是重载)。
  • 与返回类型无关,你不能仅通过返回类型不同来定义一个重载方法,编译器会报错。
  • 与访问修饰符、异常无关,这些不同不会构成重载。

作用

  • 提高代码的可读性:让方法名更直观,print(String)print(int) 都叫 print,功能一目了然。
  • 方便调用:调用者可以根据传入的数据类型,自动选择最匹配的方法,无需记忆多个不同的方法名。

示例代码

public class Calculator {
    // 重载方法 1: 两个整数相加
    public int add(int a, int b) {
        System.out.println("执行 int add(int, int)");
        return a + b;
    }
    // 重载方法 2: 三个整数相加
    public int add(int a, int b, int c) {
        System.out.println("执行 int add(int, int, int)");
        return a + b + c;
    }
    // 重载方法 3: 两个 double 数相加
    public double add(double a, double b) {
        System.out.println("执行 double add(double, double)");
        return a + b;
    }
    // 错误示例:这不算重载,因为参数列表完全相同
    // public double add(int a, int b) { ... } // 编译错误!
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        calc.add(10, 20);          // 调用 add(int, int)
        calc.add(10, 20, 30);      // 调用 add(int, int, int)
        calc.add(10.5, 20.5);      // 调用 add(double, double)
    }
}

编译器如何选择?

当你调用一个重载方法时,Java 编译器会遵循以下规则来选择最合适的方法:

  1. 精确匹配:寻找参数类型完全匹配的方法。
  2. 自动类型转换:如果没有精确匹配,编译器会尝试将参数类型进行自动提升或转换(char -> int, int -> double),然后寻找匹配的方法。
  3. 可变参数:如果以上都没有,会考虑可变参数方法。
  4. 报错:如果找到多个可能匹配的方法(一个方法能匹配 int,另一个能匹配 double,而传入的是 float),编译器会报错,因为存在“模糊调用”。

方法重写

定义

子类中,创建一个与父类中方法具有相同方法名、相同参数列表、相同返回类型的方法,用于覆盖父类的实现,这体现了面向对象的多态特性。

核心规则

  • 必须有继承关系,方法重写发生在子类和父类之间。
  • 方法名必须相同
  • 参数列表必须完全相同(个数、类型、顺序)。
  • 返回类型必须相同或是其子类(这被称为“协变返回类型”,从 Java 5 开始支持)。
  • 访问修饰符的限制:子类方法的访问权限不能比父类方法的访问权限更严格
    • 父类是 public,子类也必须是 public
    • 父类是 protected,子类可以是 protectedpublic,但不能是 private
  • 异常的限制:子类方法抛出的异常不能比父类方法抛出的异常更宽泛
    • 父类方法声明抛出 IOException,子类方法可以抛出 FileNotFoundExceptionIOException 的子类),但不能直接抛出 Exception

@Override 注解

强烈建议在重写方法上使用 @Override 注解。

  • 作用:它是一个编译器级别的提示,如果你给一个方法加上 @Override,但实际并没有正确地重写父类的方法(比如方法名写错了,或参数列表不同),编译器就会报错。
  • 好处:可以有效防止因拼写错误或参数不匹配导致的“看似重写,实则未重写”的 bug。

示例代码

// 父类
class Animal {
    public void move() {
        System.out.println("动物可以移动");
    }
}
// 子类
class Dog extends Animal {
    // 使用 @Override 注解来标记这是一个重写方法
    @Override
    public void move() {
        System.out.println("狗可以跑和走");
    }
    // 子类特有的方法
    public void bark() {
        System.out.println("汪汪!");
    }
}
public class TestOverride {
    public static void main(String[] args) {
        Animal myDog = new Dog(); // 多态:父类引用指向子类对象
        myDog.move(); // 调用的是 Dog 类中的 move() 方法,而不是 Animal 类的
                      // 输出: 狗可以跑和走
        // myDog.bark(); // 编译错误!Animal 类型没有 bark() 方法
    }
}

核心区别总结

特性 方法重载 方法重写
发生范围 同一个类中 父类与子类之间
方法名 必须相同 必须相同
参数列表 必须不同 必须相同
返回类型 无关 相同或是其子类(协变)
访问修饰符 无关 子类不能比父类更严格
目的 方便调用,提供多种功能 实现多态,子类定制父类行为
与继承关系 无关 必须有继承关系

常见面试题

问题:overloadoverride 的区别是什么?

重写与重载,到底有啥区别?-图2
(图片来源网络,侵删)

回答: "Overload"(重载)和 "Override"(重写)是 Java 中实现多态的两种不同方式。

  1. 重载

    • 定义:在同一个类中,定义多个同名但参数列表不同的方法。
    • 目的:为了方便调用,让方法名更直观,编译器根据你传入的参数类型和数量来决定具体调用哪个方法。
    • 关系:与类继承无关,是类内部的行为。
  2. 重写

    • 定义:在子类中,定义一个与父类中方法名、参数列表、返回类型都相同的方法,从而覆盖父类的实现。
    • 目的:为了实现多态,允许子类根据自身的需求提供特定的实现。
    • 关系:必须有父类和子类的继承关系。

重载是“一个类里有多个同名方法”,而重写是“子类把父类的方法实现给换了”。

重写与重载,到底有啥区别?-图3
(图片来源网络,侵删)

希望这个详细的解释能帮助你彻底理解这两个概念!

分享:
扫描分享到社交APP
上一篇
下一篇