跳到内容

元数据卡

  • 前置知识:方法定义与调用、参数传递(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))→ 调用第一个版本 你传三个参数、第三个是 Stringforge("橡木", 4, "盾"))→ 调用第二个版本 你传三个参数、第三个是 intforge("龙鳞", 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.0
cpp
// 编译错误:仅返回类型不同
int calc(int a) { return a * 2; }
double calc(int a) { return a * 2.0; }

C++ 差异:

老陈补充道:"C++ 在这点上比 Java 方便一点——它支持默认参数,少写很多重载。"

C++ 的重载规则和 Java 几乎一样。但 C++ 还支持默认参数,这可以替代一部分重载:

cpp
std::string forge(const std::string& material, int level = 3) {
    // ...
}
// 可以只传一个参数调用: forge("铁")

Java 没有默认参数——重载是唯一的替代方案。不过 Java 22 开始预览了,但在惯用法上默认参数还不是官方特性。

什么场景用重载?

  1. 构造函数重载(第7章细讲)——同一个对象的不同初始化方式
  2. 同一操作,不同输入——今天学的 forge,不同类型不同数量的材料
  3. 渐进的便利方法——一个"完全版"方法做所有事,几个"快捷版"方法用默认值调用它
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++ 额外支持默认参数,可以减少重载的数量

下一步

你已经学会了把不同任务拆成不同的方法,还学会了用重载让同一个方法名做不同的事。但有一个更深刻的问题:当你调用一个方法时,电脑在背后做了什么?它怎么知道去哪执行,执行完了怎么回来?

下一节 调用栈,我们一起老陈的铁匠铺里搭一座高塔。

Built with VitePress | Software Systems Atlas