Java 中方法重写与方法重载的区别
面试速答
重载(Overload):方法名相同,参数列表不同。编译器根据实参在编译期选择方法,属于静态绑定。
重写(Override):子类重新实现父类的实例方法。调用哪个版本由对象的运行时类型决定,属于动态绑定。
一句话记忆:重载看参数,编译期确定;重写看对象,运行期确定。
重载与重写对比
| 对比项 | 方法重载 | 方法重写 |
|---|---|---|
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须不同 | 必须相同 |
| 返回值 | 可以不同,但不能单独作为重载依据 | 相同或为父类返回类型的子类 |
| 访问权限 | 没有特殊限制 | 不能比父类方法更严格 |
| 检查异常 | 没有特殊限制 | 不能声明更宽泛的新检查异常 |
| 绑定时机 | 编译期 | 运行期 |
| 多态类型 | 编译时多态 | 运行时多态 |
方法重载
核心规则
重载要求方法名相同、参数列表不同。参数的个数、类型或顺序不同都可以构成重载。
返回值和参数名不参与重载区分。只修改返回值或参数名,会因为方法签名重复而编译失败。
class Calculator {
int add(int a, int b) {
return a + b;
}
long add(long a, long b) {
return a + b;
}
int add(int a, int b, int c) {
return a + b + c;
}
}
构造方法可以重载,因为同一个类可以提供多组不同的构造参数。
方法重写
核心规则
- 父子类方法的名称和参数列表必须相同。
- 返回类型必须相同,或者是父类方法返回类型的子类,即协变返回类型。
- 子类方法的访问权限不能更严格。
- 子类方法不能声明比父类方法更宽泛的新检查异常,运行时异常不受该限制。
- 建议始终使用
@Override,让编译器帮助检查。
class Animal {
Animal create() {
return new Animal();
}
void speak() {
System.out.println("Animal");
}
}
class Dog extends Animal {
@Override
Dog create() { // 协变返回类型
return new Dog();
}
@Override
void speak() {
System.out.println("Dog");
}
}
Animal animal = new Dog();
animal.speak(); // Dog
哪些方法不能重写
| 方法类型 | 结论 |
|---|---|
private |
对子类不可见,不参与继承,因此不能重写 |
final |
可以继承,但明确禁止子类重写 |
static |
子类同签名静态方法是隐藏,不是重写,调用在编译期绑定 |
| 构造方法 | 不会被继承,可以重载,不能重写 |
static 方法隐藏
class Parent {
static void staticMethod() {
System.out.println("Parent static");
}
void instanceMethod() {
System.out.println("Parent instance");
}
}
class Child extends Parent {
static void staticMethod() {
System.out.println("Child static");
}
@Override
void instanceMethod() {
System.out.println("Child instance");
}
}
Parent value = new Child();
value.staticMethod(); // Parent static:看引用类型
value.instanceMethod(); // Child instance:看对象类型
易错点总结
- 只改变返回值不能构成重载。
- 子类方法参数不同时是重载,不是重写。
- 字段只能被遮蔽,不能被重写。
- 静态方法是隐藏,实例方法才能通过重写实现运行时多态。
- 没有写
@Override时,一个参数类型的小错误可能让本想重写的方法变成重载。