final 修飾的目標在初始化後不可修改引用/值。編譯器據此進行優化(內聯、常量折疊),JVM 利用不可變性保證線程安全。
| 類型 | 初始化時機 | 規則 |
|---|---|---|
| 實例字段 | 聲明處 / 實例初始化塊 / 構造器 | 構造器完成前必須賦值,且僅一次 |
| 靜態字段 | 聲明處 / 靜態初始化塊 | 類加載完成前必須賦值,且僅一次 |
| 局部變量 | 首次賦值前 | 使用前必須確定賦值(定賦分析),僅一次 |
| 方法參數 | 調用時傳入 | 方法體內不可重新賦值 |
public class Demo {
final int a = 1; // 1. 聲明處
final int b; // 2. 無默認值
final int c; // 3.
{ b = 2; } // 實例初始化塊
public Demo() { // 構造器
c = 3; // 必須在這裡賦值
}
public Demo(int x) {
this(); // 委託構造器,c 已初始化
// c = x; // 編譯錯誤:final 已賦值
}
}
public void startTask(final int id) { // JDK 7 必須 final
new Thread(() -> System.out.println(id)).start(); // 捕獲
}
// JDK 8+ 「實際上 final」無需顯式 final
public void startTask(int id) { // 未修改 id 即可
new Thread(() -> System.out.println(id)).start();
}
@Override 編譯錯誤)。final 提示作用較小。public final void template() 防止子類破壞流程。extends FinalClass 編譯錯誤)。final(字段不受影響)。String, Integer, LocalDate 等不可變類、工具類 Math, Collections。SecurityManager 相關)。final 變量 ≠ 不可變對象。final 只保證引用不變,對象內部狀態仍可修改。
final List list = new ArrayList<>();
list.add("A"); // 合法!final 只鎖定引用
// list = new ArrayList<>(); // 編譯錯誤
public final class ImmutablePoint {
private final int x; // 基本類型 final = 值不可變
private final int y;
public ImmutablePoint(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() { return x; }
public int getY() { return y; }
// 無 setter,無可變方法
// 如需修改 → 返回新對象
public ImmutablePoint translate(int dx, int dy) {
return new ImmutablePoint(x + dx, y + dy);
}
}
public class Constants {
public static final int MAX_SIZE = 100; // 編譯期常量
public static final String NAME = "App"; // 編譯期常量
public static final List LIST = List.of(); // 非編譯期常量(引用)
}
// 使用處編譯期直接內聯
int size = Constants.MAX_SIZE; // 字節碼中直接 bipush 100
static final 基本類型/String + 編譯期可計算表達式 → 編譯期常量,調用處直接內聯值。new Object()、集合)不內聯,讀取字段值。native 方法:Java 聲明,實現由 C/C++ 等本地代碼在 JVM 內部完成(JNI)。
public native void registerNatives();Object.registerNatives(), System.arraycopy(), Thread.start0(), Class.forName0()。