1. 方法重载
方法重载(method overloading)是指在同一个类中,可以声明多个同名方法,但它们的参数列表(类型、数量或顺序)不同。当你调用该方法时,编译器会根据传入的参数自动决定使用哪个版本。
生活类比
想象你在拨打银行客服。你可以拨打不同的号码——个人客户、企业客户、VIP 客户。号码不同,但目的相同——获得帮助。在编程中,方法重载就像是一个统一的客服号码,它会根据你的问题(也就是你传入的参数)自动把你接入到合适的坐席。
Java 中的重载语法
在 Java 中,实现方法重载很简单:声明多个同名方法,但参数不同。
重要规则:
重载仅依据参数列表(类型、数量、顺序)来区分。
不能仅按返回类型进行重载!
如果方法的名称和参数相同,即使返回类型不同,编译器也无法区分它们。
简单示例
public class Printer {
// 打印整数
void print(int x) {
System.out.println("int: " + x);
}
// 打印字符串
void print(String s) {
System.out.println("String: " + s);
}
// 打印两个数字
void print(int x, int y) {
System.out.println("int, int: " + x + ", " + y);
}
}
用法:
Printer printer = new Printer();
printer.print(42); // 将调用 print(int x)
printer.print("Hello!"); // 将调用 print(String s)
printer.print(5, 10); // 将调用 print(int x, int y)
编译器会根据传入的参数自动确定该调用哪个方法。
2. 编译器如何选择合适的方法
当你调用一个被重载的方法时,编译器会分析参数列表并寻找最合适的版本。
选择标准:
- 参数数量匹配。
- 每个参数的类型匹配(或可以进行类型转换,例如从 int → double)。
- 若多个方法都匹配,则选择更具体的那个。
示例:
public class OverloadDemo {
void show(int x) {
System.out.println("show(int): " + x);
}
void show(double x) {
System.out.println("show(double): " + x);
}
public static void main(String[] args) {
OverloadDemo demo = new OverloadDemo();
demo.show(5); // show(int): 5
demo.show(5.5); // show(double): 5.5
}
}
如果调用 demo.show(5),编译器会选择 show(int)。如果参数是 5.5 —— 会选择 show(double)。
类型转换
如果没有完全匹配的方法,编译器会尝试对参数类型做转换(例如从 int → double),但前提是转换可行且不产生歧义。
void print(double x) { /* ... */ }
print(5); // int 5 会转换为 double 5.0
仅按返回类型重载——不可行!
很多初学者会尝试这样写:
// 错误!这种重载是不允许的
int sum(int x, int y) { return x + y; }
double sum(int x, int y) { return (double) (x + y); }
如果只是写 sum(2, 3),编译器无法知道你想调用哪一个方法。
记住:方法重载只能基于参数,而不是返回类型!
3. 构造器的重载
不仅普通方法可以重载,构造器也可以重载!
public class Person {
String name;
int age;
// 只有名字的构造器
public Person(String name) {
this.name = name;
this.age = 0; // 默认值
}
// 同时包含名字和年龄的构造器
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
用法:
Person p1 = new Person("安娜");
Person p2 = new Person("鲍里斯", 25);
4. 实用示例
带有重载的 Calculator
让我们编写一个 Calculator 类,它能对不同类型和数量的数字执行加法。
public class Calculator {
// 两个整数相加
int add(int a, int b) {
return a + b;
}
// 三个整数相加
int add(int a, int b, int c) {
return a + b + c;
}
// 两个 double 相加
double add(double a, double b) {
return a + b;
}
}
用法:
Calculator calc = new Calculator();
System.out.println(calc.add(2, 3)); // 5
System.out.println(calc.add(1, 2, 3)); // 6
System.out.println(calc.add(2.5, 3.1)); // 5.6
标准库中的方法重载
即使你没有注意过,其实你已经用过重载了。比如,System.out 中的 println 针对不同类型做了重载:
System.out.println("Hello"); // println(String)
System.out.println(123); // println(int)
System.out.println(3.14); // println(double)
System.out.println(true); // println(boolean)
打开 PrintStream 的源码——你会看到几十个重载的 println 版本。
5. 何时使用重载
方法重载是一个强大的工具,但要谨慎使用。它适用于以下场景:
- 方法的核心逻辑相同,但参数可能不同。
- 希望让类的 API 更加友好且灵活。
- 需要同时支持旧的和新的调用方式。
实际示例:
在我们的教学应用(例如一个任务管理器)中,可以用不同参数来实现添加任务的方法:
public class TaskManager {
void addTask(String description) { ... }
void addTask(String description, int priority) { ... }
void addTask(String description, int priority, String deadline) { ... }
}
这种方式不仅便于代码使用者,也让你的类对未来的变化更具弹性。
6. 重载与 varargs(可变参数)
在 Java 中,可以使用 ...(varargs)声明带有可变参数数量的方法:
void printAll(String... messages) {
for (String msg : messages) {
System.out.println(msg);
}
}
现在可以这样调用:
printAll("Hello");
printAll("One", "Two", "Three");
也可以与其他重载共存,但要小心:如果既有 varargs 方法,又有固定参数数量的方法,编译器会优先选择精确匹配的版本。
7. 方法重载的常见错误
错误 1:参数类型混淆。
如果你同时有方法 void process(int x) 和 void process(double x),调用 process(5) 会选择第一个版本,而 process(5.0) 会选择第二个。如果调用 process(5L),编译器会寻找最佳匹配,可能会选择一个不那么直观的重载(甚至报告歧义)。
错误 2:与自动装箱/类型转换相关的重载。
如果你有 void foo(Integer x) 和 void foo(Long x),调用 foo(5) 可能导致编译错误——编译器不知道该选哪个方法,因为 5 既可能与 Integer 相关,也可能与 Long 相关,可能产生歧义。
错误 3:仅按返回类型重载。
如上所述,仅返回类型不同的方法不能构成重载。
错误 4:重载与继承。
如果在基类中声明了一个方法,而你在子类中声明了同名但不同签名的方法,这属于重载而非重写。很多人会把它们混淆!关于这点的详细内容——在下一讲中。
GO TO FULL VERSION