final 語義:「不可變更」或「最終態」,按修飾目標分四類場景。
public class Test1 {
public void f1() { System.out.println("f1"); }
public final void f2() { System.out.println("f2"); } // 鎖定實現
public void f3() { System.out.println("f3"); }
private void f4() { System.out.println("f4"); } // 隱式 final
}
public class Test2 extends Test1 {
public void f1() { System.out.println("父類 f1 被覆寫"); }
// public void f2() {} // 編譯錯誤
public void f3() { System.out.println("父類 f3 被覆寫"); }
// f4 不可見,無法覆寫
}
雙重動機:
inline)調用,消除虛調用開銷| 類型 | 修飾位置 | 初始化時機 | 存儲 |
|---|---|---|---|
| 靜態常量 | static final | 聲明處/靜態塊 | 方法區 |
| 實例常量 | final 實例字段 | 聲明處/構造器/實例塊 | 堆(對象內) |
| 局部常量 | final 區域變量 | 首次賦值前 | 棧幀 |
public class Test3 {
public final int E; // 必須在構造器初始化
public Test3(int x) { E = x; } // 不同對象可有不同常量值
}
靈活性:延遲到構造器賦值,實現「對象級常量」。
public class Test3 {
private final String S = "final實例變量";
private final int A = 100;
public final int B = 90;
public static final int C = 80;
private static final int D = 70;
public final int E; // 空白 final
public Test3(int x) { E = x; }
// 任何賦值嘗試編譯報錯
}
public void f1(final int i) {
// i++; // 編譯錯誤
System.out.print(i);
}
配合匿名內部類捕獲局部變量時必須 final(Java 8+ 隱式 final)。
| 目標 | 效果 | 典型場景 |
|---|---|---|
| class | 不可繼承 | String、包裝類、安全類 |
| method | 不可覆寫 | 模板方法、核心算法、性能熱點 |
| field | 單次賦值 | 常量配置、不可變對象狀態 |
| parameter | 不可修改引用/值 | 匿名內部類捕獲、防誤改 |