經典面試題:為什麼 test(null) 調用 test(String) 而非 test(Object)?本文從 JVM 規範、編譯器解析流程、類型擬合規則三個層面,徹底講透 null 的本質與重載決策邏輯。
public class Test {
public static void main(String[] args) {
Temp temp = new Temp();
temp.test("1"); // 輸出: test String
temp.test(null); // 輸出: test String (而非 test Object)
}
}
class Temp {
public void test(Object a) { System.out.println("test Object"); }
public void test(String a) { System.out.println("test String"); }
}
null 無類型,但可賦值給任何引用類型String 比 Object 更具體null 可轉給 Object 和 String,兩者均適用String 是 Object 子類型 → test(String) 勝出Java 重載是靜態綁定(Static Binding),編譯期根據引用類型決定調用哪個方法簽名。null 沒有運行時類型,只能靠編譯期的靜態類型推斷。若是覆寫,則是動態綁定,看實際對象類型。
null
│
├─→ Object (適用)
│
└─→ String (適用,更具體) ← 編譯器選擇這個
│
└─→ Object (父類)
void test(CharSequence a) { ... } // 新增
// 原來 test(null) 調用 test(String)
// 現在 CharSequence 和 String 同級,無「最具體」 → 編譯報錯:ambiguous
對策:避免在重載鏈中引入平級類型,或顯式轉型 test((String)null)。
void test(int a) { ... }
void test(Integer a) { ... }
test(null); // 僅適用 test(Integer),基本類型不可為 null
testString()、testObject()testNull() 專用方法temp.test((String)null) 消除歧義null 是「無類型的引用值」,重載解析在編譯期按「最具體適用原則」選擇 String 而非 Object。理解 JLS 15.12 規範,能避免 90% 的重載陷阱。