3. 方法重写(Override)和方法重载(Overload)的区别?(面试官考核目标:考察编译期静态绑定与运行期动态绑定的区别)
方法重写(Override)与方法重载(Overload)的区别
一句话回答
- 重载(Overload):同一个类中,方法名相同、参数列表不同,是编译期静态绑定。
- 重写(Override):子类重新实现父类的方法,方法签名相同,是运行期动态绑定。
- 本质区别:重载看“编译时选哪个方法”,重写看“运行时调用哪个对象的方法”。
1. 核心对比
| 维度 | 重载 Overload | 重写 Override |
|---|---|---|
| 发生位置 | 同一个类中(或父子类中也可构成重载) | 子类与父类之间 |
| 方法名 | 相同 | 相同 |
| 参数列表 | 必须不同(类型、个数、顺序) | 必须相同 |
| 返回值 | 可以不同 | 必须相同或是父类返回值的子类型(协变返回) |
| 访问修饰符 | 无关 | 不能比父类更严格 |
| 异常 | 无关 | 不能抛出比父类更宽的受检异常 |
| 绑定时机 | 编译期(静态绑定) | 运行期(动态绑定) |
| 多态类型 | 编译时多态 | 运行时多态 |
| 关键修饰 | 无 | @Override(建议加) |
| 决定因素 | 参数的静态类型 | 对象的实际类型 |
记忆:重载看参数,重写看对象。重载编译定,重写运行定。
2. 重载 Overload
定义
同一个类中,方法名相同,参数列表不同。
参数列表不同包括:参数个数不同、参数类型不同、参数顺序不同。
例子
public class Calculator {
public int add(int a, int b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
public double add(double a, double b) {
return a + b;
}
public String add(String a, String b) {
return a + b;
}
}
不能构成重载的情况
public int add(int a, int b) { return a + b; }
// 编译错误:仅返回值不同,不构成重载
public double add(int a, int b) { return a + b; }
// 编译错误:仅参数名不同,不构成重载
public int add(int x, int y) { return x + y; }
只有返回值不同、参数名不同、访问修饰符不同、抛异常不同,都不构成重载。
编译期如何选择
编译器根据方法名 + 参数静态类型在编译期确定调用哪个方法。
Calculator c = new Calculator();
c.add(1, 2); // 编译期确定调用 add(int, int)
c.add(1.0, 2.0); // 编译期确定调用 add(double, double)
重载解析顺序(简化)
- 精确匹配
- 基本类型自动提升(如
int→long→float→double) - 自动装箱/拆箱
- 可变参数
void f(int x) { System.out.println("int"); }
void f(long x) { System.out.println("long"); }
void f(Integer x){ System.out.println("Integer"); }
f(1); // 输出 int,精确匹配优先
注意:
null作为参数时可能产生歧义,编译报错。
3. 重写 Override
定义
子类定义与父类方法签名相同的方法,覆盖父类实现。
例子
class Animal {
public void makeSound() {
System.out.println("动物叫声");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("汪汪");
}
}
重写规则
- 方法名相同
- 参数列表相同
- 返回值相同,或为父类返回值的子类型(协变返回)
- 访问权限不能更严格:父类
protected,子类不能是private - 不能抛出更宽的受检异常
- 不能重写
final、static、private方法(static是隐藏,private不可见) - 建议加
@Override,让编译器帮你检查
协变返回示例
class Parent {
Number get() { return 1; }
}
class Child extends Parent {
@Override
Integer get() { return 1; } // 返回值是 Number 的子类型,合法
}
运行期如何选择
运行时根据对象的实际类型决定调用哪个方法,这叫动态绑定 / 虚方法分派。
Animal a = new Dog();
a.makeSound(); // 输出“汪汪”,看实际对象是 Dog,不是看变量类型 Animal
变量
a的静态类型是Animal,编译期只检查Animal有没有makeSound();
运行期实际对象是Dog,所以调用Dog.makeSound()。
4. 静态绑定 vs 动态绑定
静态绑定(编译期)
- 发生在编译期。
- 依据:变量的静态类型、方法签名、参数类型。
- 适用:重载、
static方法、private方法、final方法、构造器。 - 优点:快,编译期就能确定。
class A {
static void hello() { System.out.println("A"); }
}
class B extends A {
static void hello() { System.out.println("B"); }
}
A a = new B();
a.hello(); // 输出 A,静态方法看静态类型,编译期绑定
动态绑定(运行期)
- 发生在运行期。
- 依据:对象的实际类型。
- 适用:重写(实例方法)。
- 实现:JVM 通过虚方法表(vtable)或方法表进行动态分派。
class A {
void hello() { System.out.println("A"); }
}
class B extends A {
@Override
void hello() { System.out.println("B"); }
}
A a = new B();
a.hello(); // 输出 B,实例方法看实际类型,运行期绑定
对比记忆:
static方法看左边(静态类型),实例重写方法看右边(实际对象)。
5. 重载与重写结合的例子
class Parent {
public void print(int x) {
System.out.println("Parent int");
}
public void print(String s) {
System.out.println("Parent String");
}
}
class Child extends Parent {
@Override
public void print(int x) {
System.out.println("Child int");
}
// 这是重载,不是重写:参数列表不同
public void print(double x) {
System.out.println("Child double");
}
}
Parent p = new Child();
p.print(1); // 运行期重写:Child int
p.print("hi"); // Parent String
Child c = new Child();
c.print(1); // Child int
c.print(1.0); // 编译期重载:Child double
关键:
先由编译器按静态类型做重载解析,选出候选方法;
再在运行期按实际类型做动态分派,决定最终执行哪个重写版本。
6. 面试口述版
重载和重写是两回事。
重载是同一个类中方法名相同、参数列表不同,和返回值、访问修饰符无关。它在编译期根据参数的静态类型确定调用哪个方法,属于静态绑定,也叫编译时多态。
重写是子类重新实现父类的方法,要求方法名、参数列表相同,返回值相同或是子类型,访问权限不能更严格,不能抛出更宽的受检异常。它在运行期根据对象的实际类型决定调用哪个方法,属于动态绑定,也叫运行时多态。JVM 通过虚方法表实现动态分派。
一句话:重载看参数,编译期定;重写看对象,运行期定。
7. 常见追问
-
重载能发生在父子类之间吗?
能。子类定义与父类同名但参数不同的方法,也构成重载;但通常不推荐,容易混淆。 -
static方法能被重写吗?
不能。子类定义同名同参的static方法是隐藏(hide),不是重写,按静态类型绑定。 -
private方法能被重写吗?
不能。private方法对子类不可见,子类定义同名方法只是新方法。 -
final方法能被重写吗?
不能。 -
构造器能被重写吗?
不能。构造器不能被继承,也谈不上重写,但可以重载。 -
重写时返回值能不同吗?
可以协变:子类返回值是父类返回值的子类型。 -
为什么重写不能缩小访问权限?
违反里氏替换原则:父类引用能调用的方法,子类对象也必须能调用。 -
动态绑定怎么实现的?
JVM 为每个类维护方法表,对象头指向类元数据,调用实例方法时按实际类型查表分派。

浙公网安备 33010602011771号