摘要
Java中重载和重写经常搞混:重载是同一个类里方法名相同、参数列表不同的多个方法,编译期就确定调用哪个;重写是子类重新实现父类同签名的方法,运行时动态绑定,是多态的核心。
重载(Overload)与重写(Override)的区别
这两个概念名字很像,但完全是两回事。重载发生在同一个类里,重写发生在父子类之间。下面从多个维度对比。
一、一句话概括
| 概念 | 一句话 |
|---|---|
| 重载 Overload | 同一个类中,方法名相同、参数列表不同的多个方法 |
| 重写 Override | 子类重新实现父类中方法签名相同的方法 |
二、核心区别对比表
| 对比维度 | 重载 Overload | 重写 Override |
|---|---|---|
| 发生位置 | 同一个类中 | 父类与子类之间 |
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须不同(个数/类型/顺序) | 必须相同 |
| 返回值类型 | 可以不同 | 必须相同(或是其子类型,协变返回) |
| 访问修饰符 | 无限制 | 不能比父类更严格 |
| 异常 | 无限制 | 不能抛出比父类更宽的检查异常 |
| 绑定时机 | 编译时(静态绑定) | 运行时(动态绑定/多态) |
| 多态体现 | 否 | 是(运行时多态) |
static 方法 | 可以重载 | 不能重写(但可被隐藏) |
final 方法 | 可以重载 | 不能重写 |
private 方法 | 可以重载 | 不能重写(子类看不到) |
三、重载(Overload)详解
定义
在同一个类中,定义多个同名但参数不同的方法。
示例(就是你之前看到的 Response)
public class Response<T> {
public static <T> Response<T> success() { ... } // 无参
public static <T> Response<T> success(T data) { ... } // 一个参数
public static <T> Response<T> success(String msg, T data) { ... } // 两个参数
}
三个 success,参数列表不同 → 重载。
关键规则
- 只看参数列表(个数、类型、顺序),与返回值无关。
- 返回值不同不算重载,会编译报错:
public int foo() { return 1; }
public String foo() { return "a"; } // ❌ 编译错误:仅返回值不同不算重载
- 调用哪个方法在编译期就确定了(静态绑定)。
常见用途
- 提供多种调用方式,方便使用(如上面的
success)。 - 构造器重载(
new ArrayList()/new ArrayList<>(10))。
四、重写(Override)详解
定义
子类重新实现父类中已有的方法,要求方法签名(方法名 + 参数列表 + 返回值)一致。
示例
class Animal {
public void sound() {
System.out.println("动物叫");
}
}
class Dog extends Animal {
@Override
public void sound() { // 重写父类方法
System.out.println("汪汪汪");
}
}
关键规则
- 方法名、参数列表必须相同。
- 返回值必须相同,或是父类返回值的子类型(协变返回)。
- 访问权限不能变小:父类
public,子类不能改成protected。 - 不能抛出更宽的检查异常。
private、static、final方法不能被重写。- 建议加
@Override注解,编译器帮你检查是否写错。
多态体现
Animal a = new Dog();
a.sound(); // 输出"汪汪汪",运行时才决定调用子类方法
这就是运行时多态——调用哪个方法在运行时才确定(动态绑定)。
五、一个直观的类比
想象一家餐厅的菜单:
- 重载:菜单上有「咖啡」、「咖啡加奶」、「咖啡加奶加糖」——同一类东西,参数不同。
- 重写:老店有「招牌菜」,新分店把「招牌菜」的做法改了,但菜名一样——子类改了父类的实现。
六、放在一起的完整示例
class Parent {
public void print() {
System.out.println("父类 print");
}
}
class Child extends Parent {
// ✅ 重写:方法名、参数、返回值都相同
@Override
public void print() {
System.out.println("子类 print");
}
// ✅ 重载:在子类中新增一个同名但参数不同的方法
public void print(String msg) {
System.out.println("子类 print: " + msg);
}
}
public class Test {
public static void main(String[] args) {
Child c = new Child();
c.print(); // 重写 → "子类 print"
c.print("hello"); // 重载 → "子类 print: hello"
Parent p = new Child();
p.print(); // 多态 → "子类 print"(运行时决定)
}
}
注意:Child 中既有重写(print())又有重载(print(String)),两者可以共存。
七、最容易混淆的点
| 疑问 | 答案 |
|---|---|
| 参数不同但方法名相同,是重写吗? | ❌ 不是,那是重载(或子类新增方法) |
| 返回值不同算重载吗? | ❌ 不算,编译报错 |
| 重写能改参数吗? | ❌ 不能,一改就变成重载了 |
| 重载是运行时多态吗? | ❌ 不是,重载是编译期决定的 |
| 重写是运行时多态吗? | ✅ 是,这是多态的核心机制 |
static 方法能被重写吗? | ❌ 不能,但可以"隐藏"(隐藏是另一个概念) |
八、总结记忆口诀
重载看参数,同类里发生,编译期决定。 重写看签名,子父类之间,运行期决定。
| 重载 | 重写 | |
|---|---|---|
| 位置 | 同类 | 父子类 |
| 参数 | 必须不同 | 必须相同 |
| 绑定 | 编译时 | 运行时 |
| 多态 | 否 | 是 |
| 关键字 | 无 | @Override |
理解这两者的关键:重载是"同名不同参",重写是"同名同参、子类改写父类逻辑"。
全部评论(0)
还没有任何评论哟~