class Dog {
public static void bark() { System.out.print("woof "); }
}
class Basenji extends Dog {
public static void bark() { /* 什麼都不做 */ }
}
public class Bark {
public static void main(String[] args) {
Dog woofer = new Dog();
Dog nipper = new Basenji(); // 多型參考
woofer.bark(); // woof
nipper.bark(); // 預期無輸出,實際輸出 woof!
}
}
輸出:woof woof。為什麼 nipper 明明是 Basenji 實例,卻執行了 Dog.bark()?
nipper 宣告為 Dog,所以編譯器直接綁定 Dog.bark(),執行期完全不看實際物件類型。JLS §15.12.4.4 明確規定:靜態方法呼叫不存在動態分派機制。
| 特性 | 覆寫 | 隱藏 |
|---|---|---|
| 方法類型 | 非靜態實例方法 | 靜態方法 |
| 綁定時機 | 執行期(動態) | 編譯期(靜態) |
| 多型支援 | ✅ | ❌ |
| @Override 註解 | 編譯器檢查 | 編譯器不檢查(Java 8+ 允許加但無意義) |
| 父類呼叫語法 | super.method() | ParentClass.method() |
子類定義相同簽名的靜態方法,只是在子類命名空間隱藏了父類方法,並未建立任何多型關係。
class Dog {
public void bark() { System.out.print("woof "); }
}
class Basenji extends Dog {
@Override public void bark() { /* 不叫 */ }
}
// 輸出:woof (只有 woofer 叫)
現在 nipper.bark() 會動態分派到 Basenji.bark(),實現真正的多型。
Math.max)、工廠方法、單例存取點、無狀態輔助函式。-Xlint:static 會提示「靜態方法應以類名呼叫」,避免 instance.staticMethod() 的誤導性寫法。「靜態方法覆寫」是 Java 初學者最常踩的坑之一。記住:**靜態綁定看宣告類型,動態分派看實際類型**。只要方法加了 static,就切斷了多型鏈路。理解這一點,不僅能避免生產事故,更能在設計 API 時做出正確的靜態 vs 實例決策。