什麼是方法重載
同一類中**方法名相同、參數列表不同** (個數、型別、順序) 的多個方法。編譯器根據**靜態綁定** (引用型別、實參型別) 決定呼叫哪個版本。
構成重載的三要素
| 差異點 | 範例 | 說明 |
| 參數個數 | `f()` vs `f(int a)` | 最常見 |
| 參數型別 | `f(int a)` vs `f(String s)` | 型別需明顯不同 |
| 參數順序 | `f(int a, String s)` vs `f(String s, int a)` | 順序不同即視為不同簽名 |
❌ 不構成重載的情況
- 僅返回值不同:`void f()` / `int f()` → **編譯錯誤** `method f() is already defined`
- 僅參數名不同:`f(int a)` / `f(int b)` → 同一簽名
- 僅修飾符不同:`public f()` / `private f()` → 同一簽名
- 靜態 vs 非靜態:`static void f()` / `void f()` → 同一簽名 (但可隱藏)
- 拋出異常不同:不影響簽名
完整程式碼示範
public class OverloadDemo {
// 1. 普通方法重載
public void print() { System.out.println("無參"); }
public void print(int i) { System.out.println("int: " + i); }
public void print(String s) { System.out.println("String: " + s); }
public void print(int i, String s) { System.out.println("int+String: " + i + s); }
public void print(String s, int i) { System.out.println("String+int: " + s + i); } // 順序不同
// 2. 構造器重載 (同樣規則)
public OverloadDemo() { this(0); System.out.println("無參構造"); }
public OverloadDemo(int i) { this(i, "def"); System.out.println("int構造: " + i); }
public OverloadDemo(int i, String s) { System.out.println("全參構造: " + i + s); }
// 3. 返回值不同 → 編譯錯誤 (取消註解驗證)
// public int print() { return 1; } // Error: method print() already defined
// 4. 可變參數重載 (優先級最低)
public void print(int... nums) { System.out.println("可變參數: " + nums.length); }
// 5. 泛型擦除後簽名相同 → 編譯錯誤
// public void test(List list) {}
// public void test(List list) {} // Error: same erasure
public static void main(String[] args) {
OverloadDemo demo = new OverloadDemo(); // 呼叫無參構造 → 鏈式呼叫 int → 全參
demo.print();
demo.print(100);
demo.print("Hello");
demo.print(1, "World");
demo.print("World", 2);
demo.print(1,2,3); // 匹配可變參數版本
}
}
構造器重載鏈 (this 呼叫)
public class ChainDemo {
private int x, y, z;
public ChainDemo() { this(0); } // 呼叫 int 版
public ChainDemo(int x) { this(x, 0); } // 呼叫 int,int 版
public ChainDemo(int x, int y) { this(x, y, 0); } // 呼叫全參版
public ChainDemo(int x, int y, int z) { // 真正初始化
this.x = x; this.y = y; this.z = z;
}
// 規則:this(...) 必須是構造器第一行語句
}
重載解析優先順序 (JLS 15.12.2)
- 精確匹配 (Exact Match) — 型別完全一致
- 基本型別擴大轉換 (Widening) — `int` → `long` → `float` → `double`
- 自動裝箱 (Boxing) — `int` → `Integer`
- 可變參數 — `int...` (最後才考慮)
void f(int i) {}
void f(long l) {}
void f(Integer i) {}
void f(int... i) {}
f(10); // 1. 精確匹配 int
f(10L); // 1. 精確匹配 long
f((short)10); // 2. 擴大 short→int
f(new Integer(10)); // 3. 裝箱 Integer
f(); // 4. 可變參數 (空陣列)
常見陷阱與最佳實踐
| 陷阱 | 後果 | 解決 |
| 基本型別 vs 包裝型別重載 | 自動拆箱/裝箱導致歧義 | 避免同時提供 `f(int)` 和 `f(Integer)` |
| 可變參數與陣列重載 | `f(int[])` vs `f(int...)` 簽名相同 | 二選一,別同時存在 |
| 泛型擦除導致衝突 | `f(List)` vs `f(List)` | 改用不同方法名或單一方法 |
| 重載過多導致可讀性下降 | 呼叫端難判斷走哪個版本 | 改用建構者模式、參數物件、或不同語意方法名 |
重載 vs 覆寫 對照
| 維度 | 重載 | 覆寫 |
| 發生位置 | 同一類 | 父子類 |
| 方法名 | 相同 | 相同 |
| 參數列表 | 必須不同 | 必須相同 |
| 返回值 | 可不同 (但不構成重載) | 兼容 (协变返回) |
| 存取修飾符 | 無限制 | 不能更嚴格 |
| 綁定時機 | 編譯期 (靜態) | 執行期 (動態) |
掌握重載規則與解析優先順序,能避免「明明有對應方法卻報錯」或「呼叫了非預期版本」的疑難雜症,也是面試高頻考點。
- 上一篇文章: Java 統計專案程式碼行數:總行、程式碼行、註解行、空白行
- 下一篇文章: Java Swing 仿 QQ 登入介面完整實作
Copyright ©
程式碼之家 All Rights Reserved