- 方法重载:就像一个厨房里可以有多个功能相似但参数不同的“榨汁机”,你可以放苹果(
juice(Apple a)),也可以放橙子(juice(Orange o)),还可以放一杯现成的果汁让它混合(juice(Juice j)),这些方法都叫“榨汁”,但能处理的东西不同。 - 方法重写:就像一个家族里,父亲会开车,儿子也学会了开车,儿子开车的方式(方法实现)和父亲可能不同(比如儿子开得更快,或者用的是自动驾驶),但“开车”这个行为(方法名)和它能完成的事情(返回类型、参数列表)是一样的,儿子用自己的方式覆盖了父亲的方式。
方法重载
定义
在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同(参数个数、参数类型或参数顺序不同)即可。

核心规则
- 方法名必须相同。
- 参数列表必须不同,这是区分重载方法的关键。
- 参数个数不同。
- 参数类型不同。
- 参数顺序不同(
method(int, String)和method(String, int)是重载)。
- 与返回类型无关,你不能仅通过返回类型不同来定义一个重载方法,编译器会报错。
- 与访问修饰符、异常无关,这些不同不会构成重载。
作用
- 提高代码的可读性:让方法名更直观,
print(String)和print(int)都叫print,功能一目了然。 - 方便调用:调用者可以根据传入的数据类型,自动选择最匹配的方法,无需记忆多个不同的方法名。
示例代码
public class Calculator {
// 重载方法 1: 两个整数相加
public int add(int a, int b) {
System.out.println("执行 int add(int, int)");
return a + b;
}
// 重载方法 2: 三个整数相加
public int add(int a, int b, int c) {
System.out.println("执行 int add(int, int, int)");
return a + b + c;
}
// 重载方法 3: 两个 double 数相加
public double add(double a, double b) {
System.out.println("执行 double add(double, double)");
return a + b;
}
// 错误示例:这不算重载,因为参数列表完全相同
// public double add(int a, int b) { ... } // 编译错误!
public static void main(String[] args) {
Calculator calc = new Calculator();
calc.add(10, 20); // 调用 add(int, int)
calc.add(10, 20, 30); // 调用 add(int, int, int)
calc.add(10.5, 20.5); // 调用 add(double, double)
}
}
编译器如何选择?
当你调用一个重载方法时,Java 编译器会遵循以下规则来选择最合适的方法:
- 精确匹配:寻找参数类型完全匹配的方法。
- 自动类型转换:如果没有精确匹配,编译器会尝试将参数类型进行自动提升或转换(
char->int,int->double),然后寻找匹配的方法。 - 可变参数:如果以上都没有,会考虑可变参数方法。
- 报错:如果找到多个可能匹配的方法(一个方法能匹配
int,另一个能匹配double,而传入的是float),编译器会报错,因为存在“模糊调用”。
方法重写
定义
在子类中,创建一个与父类中方法具有相同方法名、相同参数列表、相同返回类型的方法,用于覆盖父类的实现,这体现了面向对象的多态特性。
核心规则
- 必须有继承关系,方法重写发生在子类和父类之间。
- 方法名必须相同。
- 参数列表必须完全相同(个数、类型、顺序)。
- 返回类型必须相同或是其子类(这被称为“协变返回类型”,从 Java 5 开始支持)。
- 访问修饰符的限制:子类方法的访问权限不能比父类方法的访问权限更严格。
- 父类是
public,子类也必须是public。 - 父类是
protected,子类可以是protected或public,但不能是private。
- 父类是
- 异常的限制:子类方法抛出的异常不能比父类方法抛出的异常更宽泛。
- 父类方法声明抛出
IOException,子类方法可以抛出FileNotFoundException(IOException的子类),但不能直接抛出Exception。
- 父类方法声明抛出
@Override 注解
强烈建议在重写方法上使用 @Override 注解。
- 作用:它是一个编译器级别的提示,如果你给一个方法加上
@Override,但实际并没有正确地重写父类的方法(比如方法名写错了,或参数列表不同),编译器就会报错。 - 好处:可以有效防止因拼写错误或参数不匹配导致的“看似重写,实则未重写”的 bug。
示例代码
// 父类
class Animal {
public void move() {
System.out.println("动物可以移动");
}
}
// 子类
class Dog extends Animal {
// 使用 @Override 注解来标记这是一个重写方法
@Override
public void move() {
System.out.println("狗可以跑和走");
}
// 子类特有的方法
public void bark() {
System.out.println("汪汪!");
}
}
public class TestOverride {
public static void main(String[] args) {
Animal myDog = new Dog(); // 多态:父类引用指向子类对象
myDog.move(); // 调用的是 Dog 类中的 move() 方法,而不是 Animal 类的
// 输出: 狗可以跑和走
// myDog.bark(); // 编译错误!Animal 类型没有 bark() 方法
}
}
核心区别总结
| 特性 | 方法重载 | 方法重写 |
|---|---|---|
| 发生范围 | 同一个类中 | 父类与子类之间 |
| 方法名 | 必须相同 | 必须相同 |
| 参数列表 | 必须不同 | 必须相同 |
| 返回类型 | 无关 | 相同或是其子类(协变) |
| 访问修饰符 | 无关 | 子类不能比父类更严格 |
| 目的 | 方便调用,提供多种功能 | 实现多态,子类定制父类行为 |
| 与继承关系 | 无关 | 必须有继承关系 |
常见面试题
问题:overload 和 override 的区别是什么?

回答: "Overload"(重载)和 "Override"(重写)是 Java 中实现多态的两种不同方式。
-
重载:
- 定义:在同一个类中,定义多个同名但参数列表不同的方法。
- 目的:为了方便调用,让方法名更直观,编译器根据你传入的参数类型和数量来决定具体调用哪个方法。
- 关系:与类继承无关,是类内部的行为。
-
重写:
- 定义:在子类中,定义一个与父类中方法名、参数列表、返回类型都相同的方法,从而覆盖父类的实现。
- 目的:为了实现多态,允许子类根据自身的需求提供特定的实现。
- 关系:必须有父类和子类的继承关系。
重载是“一个类里有多个同名方法”,而重写是“子类把父类的方法实现给换了”。

希望这个详细的解释能帮助你彻底理解这两个概念!
