重载(Overloading)就是同样的一个方法能够根据输入数据的不同,做出不同的处理,而重写(Overriding)就是当子类继承自父类的相同方法,输入数据一样,但要做出有别于父类的响应时,你就要覆盖父类方法。
1. 定义不同
- 重载:在同一个类中,允许存在多个同名方法,只要它们的参数列表不同(参数个数、参数类型、参数顺序至少有一项不同)。方法的返回类型和访问修饰符可以相同也可以不同,但不能仅通过返回类型来区分重载的方法。
- 重写:在子类中,如果子类的方法与父类中的某个方法具有相同的方法名、返回类型(或兼容的返回类型)以及参数列表,则称子类的方法重写了父类的方法。
2. 范围不同
- 重载:是发生在同一个类中的。
- 重写:是发生在子类与父类之间的。
3. 多态性不同
- 重载:体现的是编译时的多态性。编译器在编译时会根据方法的参数列表确定调用哪个方法。
- 重写:体现的是运行时的多态性。当通过父类引用调用被子类重写的方法时,实际执行的是子类中的方法。
4. 参数不同
- 重载:参数个数、参数类型、参数顺序可以不同。
- 重写:父子方法参数必须相同。
5. 修饰符不同
- 重载:对修饰范围没有要求,访问修饰符(如public、protected、private)可以不同。
- 重写:要求重写方法的访问修饰符的限制一定要大于或等于被重写方法的访问修饰符。例如,如果父类中的方法是protected,那么子类中的重写方法可以是protected或public,但不能是private。
6. 返回值不同
- 重载:对返回类型没有要求,可以相同也可以不同。
- 重写:要求返回类型相同或兼容。在某些情况下(如协变返回类型),子类方法的返回类型可以是父类方法返回类型的子类。
7. 关键字不同
- 重载:不需要任何特殊的关键字。
- 重写:在Java等语言中,父类中的方法通常会被声明为
virtual
(在Java中是通过方法名相同、参数列表相同来隐式实现的,没有显式的virtual
关键字),子类中的重写方法可以通过@Override
注解来明确标识这是一个重写的方法,但这不是必须的。
总结
综上:重写就是子类对父类方法的重新改造,外部样子不能改变,内部逻辑可以改变。
区别点 | 重载方法 | 重写方法 |
---|---|---|
发生范围 | 同一个类 | 子类 |
参数列表 | 必须修改 | 一定不能修改 |
返回类型 | 可修改 | 子类方法返回值类型应比父类方法返回值类型更小或相等 |
异常 | 可修改 | 子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等; |
访问修饰符 | 可修改 | 一定不能做更严格的限制(可以降低限制) |
发生阶段 | 编译期 | 运行期 |
方法的重写要遵循“两同两小一大" :
- “两同”即方法名相同、形参列表相同;
- “两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等,子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等;
- “一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。
⭐️ 关于 重写的返回值类型 这里需要额外多说明一下,上面的表述不太清晰准确:如果方法的返回类型是 void 和基本数据类型,则返回值重写时不可修改。但是如果方法的返回值是引用类型,重写时是可以返回该引用类型的子类的。
public class Hero {
public String name() {
return "超级英雄";
}
}
public class SuperMan extends Hero{
@Override
public String name() {
return "超人";
}
public Hero hero() {
return new Hero();
}
}
public class SuperSuperMan extends SuperMan {
@Override
public String name() {
return "超级超级英雄";
}
@Override
public SuperMan hero() {
return new SuperMan();
}
}