final 是 Java 中語義最豐富、誤解最多的關鍵字之一。本文系統整理其修飾基本型別變數、參考型別變數、方法、類別時的差異語義,並以程式碼實測驗證常見認知盲區。
final int NUM = 16;
final String STR = "zy"; // String 屬特殊不可變物件
// NUM = 17; // 編譯錯誤:cannot assign a value to final variable
// STR = "abc"; // 編譯錯誤
規則:編譯期常量(基本型別 + String)納入常量池;非編譯期常量(如建構子初始化的 final String str1)執行期賦值一次後鎖定。
final A a = new A(); // A 為自訂類別,含 int t 欄位
a.setT(29); // ✅ 合法:修改物件內部狀態
System.out.println(a.getT()); // 輸出 29
// a = new A(); // ❌ 編譯錯誤:cannot assign a value to final variable a
核心區別:
final 鎖定的是變數儲存的記憶體位址(引用),非物件本身。final。public class A {
public final void finalA() { ... } // 子類別不可覆寫
private void privateA() { ... } // 子類別不可見,可自行定義同名方法
private final void privateFinalA() { ... } // 雙重限制
}
public class AA extends A {
// public final void finalA() { ... } // ❌ 編譯錯誤:Cannot override final method
private void privateA() { ... } // ✅ 合法:全新私有方法,非覆寫
private final void privateFinalA() { ... } // ✅ 合法
}
重點:
final 方法可被繼承(子類別可呼叫 super.finalA()),但不可覆寫。private 方法對子類別不可見,子類別同名方法屬全新定義,不構成覆寫。public final class ImmutableClass { ... }
// class Sub extends ImmutableClass { } // ❌ 編譯錯誤
典型應用:String, Integer 等不可變類別,確保語義不被破壞。
| 修飾目標 | 語義 | 典型用途 |
|---|---|---|
| 基本型別變數 | 值不可變更 | 常數定義、編譯期常量 |
| 參考型別變數 | 引用不可指向新物件,但物件內容可變 | 集合引用、元件引用、依賴注入欄位 |
| 方法 | 禁止子類別覆寫,允許繼承與呼叫 | 模板方法模式、核心演算法鎖定、效能優化提示 |
| 類別 | 禁止被繼承 | 不可變類別、安全敏感類別、工具類 |
final List list 內容不可變 → 需配合 Collections.unmodifiableList() 或不可變集合實作。final 欄位 → 編譯錯誤,必須在宣告處、實例初始化塊、或所有建構子中明確賦值。final → Java 8+ 改為「effectively final」隱性要求,但語義未變。final 不只是「最後」的意思,更是「契約」的宣示:基本型別鎖值、參考型別鎖址、方法鎖行為、類別鎖繼承。精準理解各語境語義,能避免大量運行時驚喜,寫出更健壯、自文檔化的程式碼。