方法重載是 Java 實現多態的靜態形式(編譯期多態)。本文深入剖析重載的判定規則、解析流程、易混淆陷阱與設計原則。
方法簽名 = 方法名 + 參數列表(類型、數量、順序)
| 因素 | 影響重載 | 說明 |
|---|---|---|
| 參數類型不同 | ✅ 是 | 核心區分依據 |
| 參數數量不同 | ✅ 是 | 如 sum(int a) vs sum(int a, int b) |
| 參數順序不同 | ✅ 是 | 如 foo(int, String) vs foo(String, int) |
| 返回值類型 | ❌ 否 | 編譯報錯:return type is not part of method signature |
| 訪問修飾符 | ❌ 否 | public/private/protected 無關 |
| 拋出異常 | ❌ 否 | throws 子句不影響重載 |
| 參數名稱 | ❌ 否 | 僅影響可讀性,字節碼不保留(除編譯參數) |
調用站編譯時,編譯器按優先級嘗試匹配:
Type... 作為最後備選class AmbiguityDemo {
void process(Object o) { System.out.println("Object"); }
void process(String s) { System.out.println("String"); }
void process(int i) { System.out.println("int"); }
void process(long l) { System.out.println("long"); }
void process(Integer i) { System.out.println("Integer"); }
void process(int... arr) { System.out.println("varargs"); }
public static void main(String[] args) {
AmbiguityDemo d = new AmbiguityDemo();
d.process("hello"); // String (精確)
d.process(10); // int (精確)
d.process(10L); // long (精確)
d.process(new Object()); // Object (精確)
d.process(null); // ❌ 編譯錯誤:String/Object/Integer 皆可匹配
d.process(1, 2, 3); // varargs (最後備選)
}
}
class BoxingVarargs {
void foo(Integer i) { System.out.println("Integer"); }
void foo(int... arr) { System.out.println("varargs"); }
public static void main(String[] args) {
BoxingVarargs b = new BoxingVarargs();
b.foo(10); // int → Integer (精確拆箱優於 varargs)
b.foo(new Integer(10)); // Integer (精確)
// b.foo(null); // ❌ 模糊:Integer vs varargs
}
}
| 維度 | 重載 | 重寫 |
|---|---|---|
| 發生範圍 | 同一類內 | 父子類之間 |
| 方法名 | 相同 | 相同 |
| 參數列表 | 必須不同 | 必須相同 |
| 返回類型 | 可不同 | 兼容(协变返回) |
| 訪問權限 | 無要求 | 不能縮小 |
| 拋出異常 | 無要求 | 不能擴大 |
| 綁定時間 | 編譯期(靜態) | 運行期(動態) |
| 多態類型 | 編譯期多態 | 運行期多態 |
// String 提供豐富重載滿足不同場景
public class String {
// 構造器重載
public String() {}
public String(String original) {}
public String(char[] value) {}
public String(char[] value, int offset, int count) {}
public String(int[] codePoints, int offset, int count) {}
public String(byte[] bytes, Charset charset) {}
public String(byte[] bytes, int offset, int length, Charset charset) {}
// 方法重載
public boolean startsWith(String prefix) {}
public boolean startsWith(String prefix, int toffset) {}
public int indexOf(int ch) {}
public int indexOf(int ch, int fromIndex) {}
public int indexOf(String str) {}
public int indexOf(String str, int fromIndex) {}
// ... 100+ 重載方法
}
Object、String、包裝類、可變參數重載方法重載本質是編譯期基於參數簽名的靜態分發。掌握三階段匹配規則、自動拆裝箱優先級、可變參數最低優先級,能避開 90% 重載陷阱。設計 API 時遵循「語義統一、類型精確、避免模糊」原則,讓重載成為提升開發體驗的語法糖,而非 Bug 溫床。