CodeGym /課程 /JAVA 25 SELF /方法多載(overloading)

方法多載(overloading)

JAVA 25 SELF
等級 18 , 課堂 1
開放

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 做多載,但要小心:如果同時存在一個使用 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:多載與繼承。
如果在基底類別中宣告了一個方法,而你在子類別中宣告同名但不同簽章的方法,這是多載,而不是覆寫。這點很常被混淆!詳細內容——請見下一堂課。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION