在程式語言的世界裡,類型檢查是確保程式碼安全性的關鍵防線。根據維基百科的定義,靜態類型檢查是在編譯階段基於原始碼進行驗證,而動態類型檢查則發生在程式執行期間。Java 採用靜態類型檢查策略,旨在編譯期就攔截類型錯誤,避免它們在運行時引發崩潰。
理解 Java 靜態類型檢查的關鍵在於區分「引用的宣告類型」與「物件的實際類型」。請看以下繼承關係:
class A {
A me() { return this; }
public void doA() { System.out.println("Do A"); }
}
class B extends A {
public void doB() { System.out.println("Do B"); }
}
當呼叫 new B().me() 時:
me() 宣告回傳型別為 A,因此編譯器認為這是一個 A 型別的引用。B 繼承了 me() 並回傳 this,實際回傳的是 B 物件。這種機制導致以下程式碼在編譯期非法:
// 編譯錯誤:找不到 doB() 方法 new B().me().doB();
因為編譯器只知道引用是 A 型別,而 A 類別沒有 doB() 方法。合法的呼叫僅限於:
// 編譯通過:A 類別有 doA() 方法 new B().me().doA();
開發者可以透過強制轉型繞過編譯檢查:
// 編譯通過,但執行期有風險 ((B) new B().me()).doB();
然而,若轉型目標與實際物件不符,將拋出 ClassCastException:
class C extends A { public void doBad() { ... } }
// 編譯通過,執行期拋出異常:B cannot be cast to C
((C) new B().me()).doBad();
這體現了 Java 的核心設計哲學:編譯期盡最大努力保證類型安全,執行期作為最後防線處理無法在編譯期確定的情況。
Java 的靜態類型檢查基於引用的宣告類型進行,這雖然限制了某些動態行為,但極大地提高了程式碼的可靠性與可維護性。開發者需理解「宣告類型決定編譯期可見性,實際類型決定執行期行為」這一核心原則,善用多型並謹慎使用強制轉型。