元数据卡
- 前置知识:方法定义与调用、参数传递(ch05-parameters-return)
- 预计时间:10 分钟
- 完成标志:能够运用方法重载解决同名不同参数的问题
回顾
"师傅,打剑是 forgeSword,打盾牌难道要叫 forgeShield?那打盔甲呢?forgeArmor?那要是以后还有长矛、弓箭、法杖,每个都要起不同的名字——这也太累了吧?"
第五幕:同一个名字,不同的兵器
"不用,"老陈笑了,"就叫 forge。传进来的东西不同,我做的自然不同。"
java
public class Forge {
public static void main(String[] args) {
System.out.println(forge("铁", 3)); // 打铁剑
System.out.println(forge("钢", 5)); // 打钢剑
System.out.println(forge("橡木", 4, "盾")); // 打橡木盾
System.out.println(forge("龙鳞", 2, 10)); // 打龙鳞甲,+10防御
}
// 两个参数:打剑
static String forge(String material, int level) {
return level >= 4
? "精良" + material + "剑"
: "普通" + material + "剑";
}
// 三个参数:打其他装备
static String forge(String material, int level, String type) {
return level >= 3
? "精良" + material + type
: "普通" + material + type;
}
// 三个参数,最后一个类型不同:打带防御值的盔甲
static String forge(String material, int level, int defense) {
return "防御+" + defense + "的" + material + "甲(等级" + level + ")";
}
}python
def forge(material: str, level: int) -> str:
return "精良" + material + "剑" if level >= 4 else "普通" + material + "剑"
def forge(material: str, level: int, extra) -> str:
if isinstance(extra, str):
return "精良" + material + extra if level >= 3 else "普通" + material + extra
else:
return "防御+" + str(extra) + "的" + material + "甲(等级" + str(level) + ")"
def main():
print(forge("铁", 3))
print(forge("钢", 5))
print(forge("橡木", 4, "盾"))
print(forge("龙鳞", 2, 10))
if __name__ == "__main__":
main()cpp
#include <iostream>
#include <string>
using namespace std;
string forge(const string& material, int level) {
return level >= 4
? "精良" + material + "剑"
: "普通" + material + "剑";
}
string forge(const string& material, int level, const string& type) {
return level >= 3
? "精良" + material + type
: "普通" + material + type;
}
string forge(const string& material, int level, int defense) {
return "防御+" + to_string(defense) + "的" + material + "甲(等级" + to_string(level) + ")";
}
int main() {
cout << forge("铁", 3) << endl;
cout << forge("钢", 5) << endl;
cout << forge("橡木", 4, "盾") << endl;
cout << forge("龙鳞", 2, 10) << endl;
return 0;
}语言:Java 21 如何运行:javac Forge.java && java Forge预期输出:
普通铁剑
精良钢剑
精良橡木盾
防御+10的龙鳞甲(等级2)这叫方法重载(method overloading):同一个方法名,不同参数列表。编译器根据你调用时传的参数,自己决定用哪个版本。
你传两个参数(forge("铁", 3))→ 调用第一个版本 你传三个参数、第三个是 String(forge("橡木", 4, "盾"))→ 调用第二个版本 你传三个参数、第三个是 int(forge("龙鳞", 2, 10))→ 调用第三个版本
规则一字不改:
- 必须参数列表不同(数量不同 / 类型不同 / 顺序不同)
- 光返回类型不同不够——编译器只看你传了什么,不看你要什么类型
java
// 编译错误:仅返回类型不同
static int calc(int a) { return a * 2; }
static double calc(int a) { return a * 2.0; }python
# Python 没有真正的方法重载(同名方法只会保留最后一个定义)
# 通常用默认参数或类型判断来模拟
def calc(a: int, mode: str = "int") -> int | float:
if mode == "int":
return a * 2
else:
return a * 2.0cpp
// 编译错误:仅返回类型不同
int calc(int a) { return a * 2; }
double calc(int a) { return a * 2.0; }C++ 差异:
老陈补充道:"C++ 在这点上比 Java 方便一点——它支持默认参数,少写很多重载。"
C++ 的重载规则和 Java 几乎一样。但 C++ 还支持默认参数,这可以替代一部分重载:
cppstd::string forge(const std::string& material, int level = 3) { // ... } // 可以只传一个参数调用: forge("铁")Java 没有默认参数——重载是唯一的替代方案。不过 Java 22 开始预览了,但在惯用法上默认参数还不是官方特性。
什么场景用重载?
- 构造函数重载(第7章细讲)——同一个对象的不同初始化方式
- 同一操作,不同输入——今天学的
forge,不同类型不同数量的材料 - 渐进的便利方法——一个"完全版"方法做所有事,几个"快捷版"方法用默认值调用它
java
// 渐进的便利方法——一种常用的重载模式
static void printMessage(String msg) {
printMessage(msg, 1); // 默认只打印一次
}
static void printMessage(String msg, int times) {
for (int i = 0; i < times; i++) {
System.out.println(msg);
}
}python
# Python 更自然的写法——默认参数
def print_message(msg: str, times: int = 1):
for i in range(times):
print(msg)cpp
// 默认参数——C++ 最自然的写法
void printMessage(const string& msg, int times = 1) {
for (int i = 0; i < times; i++) {
cout << msg << endl;
}
}旅人笔记
- 方法重载:同名方法,不同参数列表
- 编译器根据参数数量、类型、顺序来区分调用哪个版本
- 仅改变返回类型不够,必须改参数列表
- 重载让方法名更有表现力——一个动词,多种用法
- C++ 额外支持默认参数,可以减少重载的数量
→ 下一步
你已经学会了把不同任务拆成不同的方法,还学会了用重载让同一个方法名做不同的事。但有一个更深刻的问题:当你调用一个方法时,电脑在背后做了什么?它怎么知道去哪执行,执行完了怎么回来?
下一节 调用栈,我们一起老陈的铁匠铺里搭一座高塔。