final 表達「這部分不允許被修改」,動機有二:效能優化(編譯期常量折疊、JIT 內聯)與 設計意圖(防止繼承/覆蓋、保證線程安全不可變對象)。
| 類型 | 初始化時機 | 可變性 | 典型用法 |
|---|---|---|---|
| 編譯期常量 | 類加載階段 | 永遠不可變 | static final int MAX = 100;、基本類型 + 字面量 |
| 運行期常量 | 構造器/實例化時 | 引用不可變,對象內容可變 | final List list = new ArrayList();、final int id = random.nextInt(); |
public class FinalTest {
private final String compileConst = "chenssy"; // 編譯期常量
private final String runtimeConst; // 構造器初始化
private final int randomVal = new Random().nextInt(50); // 運行期確定
public final Person personRef = new Person("chen_ssy"); // 引用不可變
public FinalTest(String runtimeConst) { this.runtimeConst = runtimeConst; }
public static void main(String[] args) {
FinalTest t1 = new FinalTest("cm");
FinalTest t2 = new FinalTest("zj");
System.out.println(t1); // compileConst=chenssy, runtimeConst=cm, randomVal=34, personRef=chen_ssy
System.out.println(t2); // compileConst=chenssy, runtimeConst=zj, randomVal=46, personRef=chen_ssy
t2.personRef.setName("chenssy"); // 修改引用對象內部狀態 ✅ 允許
System.out.println(t2); // personRef=chenssy
}
}
關鍵點: final 修飾引用類型時,引用不可變,但指向對象的內部狀態可變。
final 提示作用減弱,但語義仍重要。final class 表示不設計繼承,典型如 String、Integer、Math。public void process(final int value) {
// value = 10; // 編譯錯誤
}
public void modify(final Person p) {
// p = new Person(); // 編譯錯誤:引用不可變
p.setName("new"); // ✅ 允許:修改對象內部狀態
}
匿名內部類場景: 外部方法參數若需被匿名內部類使用,必須聲明 final(Java 8+ 隱式 final),確保參數生命週期覆蓋內部類實例,避免引用不一致。
public static final double PI = 3.1415926;
public static final String CONFIG_PATH = "/etc/app/config";
ClassName.CONSTANT 訪問。| 修飾目標 | 不可變內容 | 典型場景 |
|---|---|---|
| 基本類型變量 | 數值 | 常量定義 |
| 引用類型變量 | 引用地址 | 集合引用、依賴注入 |
| 方法 | 方法體實現 | 模板方法、工具方法 |
| 類 | 繼承關係 | 不可變對象、工具類 |
| 參數 | 參數引用/值 | 匿名內部類、防誤賦值 |