杰瑞科技汇

Java重写与重载,核心区别在哪?

一句话核心总结

  • 重载:在同一个类中,方法名相同,但参数列表不同(参数个数、类型或顺序不同),它发生在编译时
  • 重写:在子类中,方法名、参数列表和返回类型与父类完全相同(返回类型可以是协变的),并且访问权限不能更严格,它发生在运行时,与多态密切相关。

详细对比表格

为了更直观地理解,我们可以通过一个对比表格来看它们的区别:

Java重写与重载,核心区别在哪?-图1
(图片来源网络,侵删)
特征 重载 重写
定义位置 同一个类中,或者在同一类中的父子类也可以(但通常不这么做)。 子类父类之间。
方法名 必须相同。 必须相同。
参数列表 必须不同(参数个数、类型或顺序至少有一项不同)。 必须相同
返回类型 可以相同,也可以不同。如果参数列表也相同,返回类型不同会导致编译错误 通常相同,在 Java 5+ 中,可以是协变返回类型(即子类方法的返回类型是父类方法返回类型的子类)。
异常 对抛出的异常没有特殊要求。 子类方法声明抛出的异常不能比父类方法更宽泛(即不能是父类方法异常的父类或同级)。
访问修饰符 对访问修饰符没有特殊要求。 子类方法的访问修饰符不能比父类方法的更严格(父类是 public,子类不能是 protected)。
绑定时机 编译时,编译器根据调用时传入的参数列表来决定具体调用哪个方法。 运行时,JVM 根据对象的实际类型(而不是引用类型)来决定调用哪个方法。
与多态的关系 与多态无关,它只是提供了一种在同一个类中定义多个同名方法的便利。 是多态的体现,没有重写,就没有运行时多态。
目的 功能类似,但参数不同print(String s)print(int i),实现同一个类中多种行为的“重载”。 子类需要修改或扩展父类的行为,实现基于对象类型的动态方法调用。

代码示例

通过代码示例可以更好地理解这两个概念。

重载 示例

在同一个类中,我们定义了多个 calculate 方法,它们的方法名相同,但参数列表不同。

class Calculator {
    // 重载方法 1: 两个整数相加
    public int calculate(int a, int b) {
        System.out.println("计算两个整数的和");
        return a + b;
    }
    // 重载方法 2: 三个整数相加
    public int calculate(int a, int b, int c) {
        System.out.println("计算三个整数的和");
        return a + b + c;
    }
    // 重载方法 3: 两个浮点数相加
    public double calculate(double a, double b) {
        System.out.println("计算两个双精度浮点数的和");
        return a + b;
    }
    // 这个方法会编译错误,因为它与第一个 calculate 方法签名完全相同
    // public int calculate(int x, int y) { ... }
}
public class OverloadExample {
    public static void main(String[] args) {
        Calculator calc = new Calculator();
        // 编译器根据传入的参数列表,自动选择调用哪个方法
        int sum1 = calc.calculate(10, 20);        // 调用 calculate(int, int)
        int sum2 = calc.calculate(10, 20, 30);     // 调用 calculate(int, int, int)
        double sum3 = calc.calculate(10.5, 20.5); // 调用 calculate(double, double)
        System.out.println("结果1: " + sum1);
        System.out.println("结果2: " + sum2);
        System.out.println("结果3: " + sum3);
    }
}

输出:

计算两个整数的和
计算三个整数的和
计算两个双精度浮点数的和
结果1: 30
结果2: 60
结果3: 31.0

重写 示例

我们有一个父类 Animal 和一个子类 Dog,子类 Dog 重写了父类 AnimalmakeSound 方法。

Java重写与重载,核心区别在哪?-图2
(图片来源网络,侵删)
// 父类
class Animal {
    // 父类的方法
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}
// 子类
class Dog extends Animal {
    // @Override 注解可以帮助检查是否正确地重写了父类方法
    @Override
    public void makeSound() {
        System.out.println("汪汪汪!");
    }
}
public class OverrideExample {
    public static void main(String[] args) {
        // 创建一个 Animal 对象
        Animal myAnimal = new Animal();
        myAnimal.makeSound(); // 调用 Animal 类的 makeSound 方法
        // 创建一个 Dog 对象
        Dog myDog = new Dog();
        myDog.makeSound();    // 调用 Dog 类重写后的 makeSound 方法
        // 关键部分:多态
        // 父类引用指向子类对象
        Animal myPuppy = new Dog();
        // 运行时,JVM 发现 myPuppy 的实际类型是 Dog,所以调用 Dog 的 makeSound 方法
        myPuppy.makeSound(); // 输出 "汪汪汪!"
    }
}

输出:

动物发出声音
汪汪汪!
汪汪汪!

注意最后一行 myPuppy.makeSound(); 的输出,虽然 myPuppy 的类型是 Animal,但它引用的实际对象是 new Dog(),在运行时,JVM 会根据对象的实际类型(Dog)来查找并调用 makeSound 方法,这就是运行时多态,而重写是实现它的关键。


常见误区

  1. 重载和返回类型有关吗?

    • 无关,仅当参数列表也相同时,返回类型不同才构成编译错误,如果参数列表不同,返回类型可以自由变化。
  2. 子类重写父类方法时,可以降低访问权限吗?

    Java重写与重载,核心区别在哪?-图3
    (图片来源网络,侵删)
    • 不可以,父类方法是 public,子类重写时不能是 protectedprivate,这会破坏多态的封装性。
  3. private 方法能被重写吗?

    • 不能private 方法在声明它的类之外是不可见的,因此子类无法继承它,更谈不上重写,如果子类中定义了一个与父类 private 方法同名的方法,这只是一个新的、无关的方法,不是重写。
  4. static 方法能被重写吗?

    • 不能static 方法是与类绑定的,而不是与实例对象绑定的,子类中定义一个与父类 static 方法同名的方法,这被称为方法隐藏,而不是重写,通过子类引用调用时,会调用子类的 static 方法;通过父类引用调用时,会调用父类的 static 方法。

记住这个简单的区分方法:

  • 重载看“参数”:在同一个类里,方法名一样,参数不一样。
  • 重写看“父类”:在子类里,把父类的方法“重新写一遍”,要求方法签名(方法名+参数列表)完全一样。

理解重载和重写的区别,是掌握 Java 面向对象编程,特别是多态机制的基础。

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