重载和覆写有什么区别?
重载(Overload)和覆写(Override,也叫重写 )是面向对象编程中的重要概念,它们有以下区别:
定义
- 重载:在同一类中,允许存在多个方法名相同,但参数列表(参数个数、参数类型、参数顺序)不同的方法。返回值类型可以相同也可以不同 。例如在一个 MathUtils 类中:
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
这里两个 add 方法构成了重载关系。
- 覆写:发生在具有继承关系的子类和父类之间,子类重新实现父类中定义的虚函数(在C++、Java等语言中,需用特定关键字标识,如C++的 virtual 、Java的 @Override ) ,要求方法名、参数列表、返回值类型都必须与父类被覆写方法相同,且子类方法不能比父类方法有更严格的访问控制权限。例如:
class Animal {
public void speak() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void speak() {
System.out.println("Dog barks");
}
}
Dog 类中的 speak 方法覆写了 Animal 类中的 speak 方法。
发生范围
- 重载:发生在同一个类中,是同一类中多个同名方法之间的关系,属于水平关系 。
- 覆写:基于继承关系,发生在子类与父类之间,是垂直关系 。
多态性体现
- 重载:是静态多态(编译时多态)的体现 。在编译阶段,编译器根据调用方法时传入的实参类型、个数、顺序等,确定具体调用哪个重载方法。例如 MathUtils.add(1, 2) 和 MathUtils.add(1.0, 2.0) ,编译器在编译时就能确定调用的是不同的 add 方法。
- 覆写:是动态多态(运行时多态)的体现 。程序运行时,根据对象实际所属的类型来决定调用哪个类的覆写方法。比如有 Animal animal = new Dog(); ,调用 animal.speak() 时,实际调用的是 Dog 类中覆写后的 speak 方法,这是在运行时根据 animal 实际指向的对象类型( Dog 类对象)来确定的。
访问权限
- 重载:对方法的访问权限没有特殊要求,各个重载方法的访问权限可以不同。
- 覆写:子类覆写的方法不能比父类被覆写方法有更严格的访问控制权限。比如父类方法是 public ,子类覆写方法不能是 private 或 protected ;若父类方法是 protected ,子类覆写方法可以是 protected 或 public 。
方法数量
- 重载:一个方法可以有多个重载版本,即同一类中可以存在多个同名但参数列表不同的方法 。
- 覆写:针对父类中的一个方法,在子类中通常只有一个覆写版本 。