final 可修飾 類、方法、變量 (含實例/靜態/局部),語義統一:定義後不可改變。本文逐一拆解三大場景、引用類型「值不變、對象可變」核心陷阱、構造器無法修飾原因、以及不可變對象設計最佳實踐。
final class Penguin { } // 不能被繼承
// class SubPenguin extends Penguin { } // 編譯錯誤:The type SubPenguin cannot subclass the final class Penguin
String、Integer)、安全敏感類、防止被惡意繼承竄改行為。final (不可重寫)。class Penguin {
public final void print() { } // 子類不能重寫
}
// class SubPenguin extends Penguin {
// public void print() { } // 編譯錯誤:Cannot override the final method from Penguin
// }
private 方法隱式 final (子類不可見,自然不可重寫)。| 變量類型 | 初始化時機 | 默認值 | 說明 |
|---|---|---|---|
| 實例變量 | 聲明時 / 構造器 / 初始化塊 (任一) | 無 | 對象創建後不可變 |
| 靜態變量 | 聲明時 / 靜態初始化塊 | 無 | 類加載後不可變,慣例大寫下劃線 |
| 局部變量 | 聲明時 / 首次賦值前 | 無 | 方法內常量 |
public class Dog {
final String name = "小黃"; // 聲明時賦值
// final int age; // 需在構造器賦值
public void setName(String name) {
this.name = name; // 編譯錯誤:Cannot assign a value to final variable 'name'
}
}
class Dog {
String name;
public Dog(String name) { this.name = name; }
}
public class FinalRefDemo {
public static void main(String[] args) {
final Dog dog = new Dog("小黃"); // dog 引用不可變
dog.name = "大黃"; // ✅ 合法!修改對象內部狀態
// dog = new Dog("小八"); // ❌ 編譯錯誤:Cannot assign a value to final variable 'dog'
}
}
final Dog dog = new Dog("小黃");
棧內存: dog ──────→ 堆內存: Dog@123 { name: "小黃" }
↑
final 鎖死引用地址
但堆對象內部字段可自由修改
final List list = new ArrayList<>();
list.add("A"); // ✅ 合法
list.clear(); // ✅ 合法
// list = new ArrayList<>(); // ❌ 編譯錯誤
結論:final 只鎖定引用地址,不鎖定對象內部狀態。真正不可變需類本身設計為不可變 (如 String、Guava ImmutableList)。
final 無意義。super()。public final class ImmutableUser {
private final String name;
private final List tags; // 可變組件
public ImmutableUser(String name, List tags) {
this.name = name;
this.tags = new ArrayList<>(tags); // 防御性拷貝
}
public String getName() { return name; }
public List getTags() {
return Collections.unmodifiableList(tags); // 返回不可變視圖
}
}
final static 基本類型/字符串常量內聯到字節碼。final 字段在構造器中寫入後,確保其他線程可見 (JMM 語義)。| 修飾目標 | 語義 | 核心限制 | 典型場景 |
|---|---|---|---|
| 類 | 不可繼承 | 不能 extends | String、工具類、安全類 |
| 方法 | 不可重寫 | 子類不能 override | 模板方法骨架、核心算法 |
| 基本類型變量 | 值不可變 | 只能賦值一次 | 常量、配置參數 |
| 引用類型變量 | 引用不可變 | 不能指向新對象,但對象內部可變 | 集合引用、對象引用 |
黃金法則:默認給變量加 final,除非確需重賦值。
final是最廉價的文檔、最強的編譯器檢查、最穩的併發保障。