final 是 Java 中表達「不可變」語義的核心關鍵字,可修飾類、方法、變量 (成員/靜態/局部)。正確使用 final 能顯著提升代碼的安全性、可讀性、可維護性,並幫助編譯器與 JVM 進行優化。本文將系統梳理其三大用法、底層語義、最佳實踐及常見誤區。
public final class ImmutableString { ... } // 如 java.lang.String
final (無法被重寫),但字段不自動成為 final。String, Integer, BigDecimal,保證核心行為不被篡改。public class Base {
public final void criticalOperation() { ... } // 子類不可重寫
public void overridable() { ... } // 允許重寫
}
private 方法隱式為 final (不可見自然不可重寫)。final 修飾構造器 (構造器不參與多態,無重寫概念)。Object.getClass() 為 final,保證運行時類型識別不可竄改。核心規則:final 變量**只能被賦值一次** (顯式賦值或構造器/靜態塊中)。
| 類型 | 不可變內容 | 示例 |
|---|---|---|
| 基本類型 | 值本身不可變 | final int MAX = 100; |
| 引用類型 | 引用地址不可變 (始終指向同一對象),但對象內部狀態可變 | final List<String> list = new ArrayList<>(); list.add("a"); // 合法 |
public class FinalDemo {
// 1. 靜態常量 (編譯期常量建議大寫+下劃線)
public static final int MAX_SIZE = 100; // 直接賦值
public static final String CONFIG_KEY; // 聲明不賦值
static { CONFIG_KEY = "app.config"; } // 必須在靜態塊初始化
// 2. 實例常量
private final Date createdAt = new Date(); // 直接賦值
private final String id; // 聲明不賦值
public FinalDemo(String id) { this.id = id; } // 必須在構造器中初始化
// 3. 局部常量 (方法內/塊內)
public void process() {
final String prefix = "LOG_"; // 直接賦值
final String suffix; // 延遲賦值
if (System.currentTimeMillis() % 2 == 0) suffix = "_EVEN";
else suffix = "_ODD"; // 每條路徑必須賦值一次
// suffix = "OTHER"; // 編譯錯誤:已賦值
}
}
構建線程安全的不可變類,final 是基石:
public final class Point { // 1. 類 final
private final int x, y; // 2. 所有字段 final + private
public Point(int x, int y) { this.x = x; this.y = y; }
public int getX() { return x; }
public int getY() { return y; }
// 3. 無 setter,修改返回新對象
public Point translate(int dx, int dy) {
return new Point(x + dx, y + dy);
}
}
Date, 數組, 集合),構造器/Getter 必須防禦性拷貝。| 誤區 | 真相 |
|---|---|
| final 引用指向的對象不可變 | **錯**!引用不可變,對象內部狀態可變。需配合不可變類設計。 |
| final 能提升所有性能 | 現代 JVM (JIT) 對非 final 也能優化 (逃逸分析、內聯)。final 主要價值在**語義約束與編譯期檢查**。 |
| 所有方法都加 final | **反模式**!殺死了多態擴展性。僅在「確定不變」的核心邏輯上使用。 |
| 構造器可用 final | **語法錯誤**。構造器不參與繼承/重寫。 |
final**,除非確需修改 (如 Builder 模式、狀態機)。final** (如 void process(final String input)),防止方法內誤重賦值,文檔意圖。final**,減少可變狀態,利於函數式風格與並發。static final 全大寫下劃線 (如 MAX_RETRY_COUNT)。final 不僅是語法糖,更是**設計意圖的聲明**與**編譯器強制的契約**。它守護著不可變性這一並發編程與領域建模的基石。善用 final,讓「不可變」成為默認選擇,將可變狀態最小化、局部化,是編寫健壯、清晰、高性能 Java 代碼的關鍵習慣。