首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java final 修飾符詳解:不可變語義、三大應用場景與編譯器優化

     編輯:Java 相關知識

final 核心語義:不可變

final 修飾的目標在初始化後不可修改引用/值。編譯器據此進行優化(內聯、常量折疊),JVM 利用不可變性保證線程安全。

三大應用目標

1. final 變量(字段/局部變量/參數)

類型初始化時機規則
實例字段聲明處 / 實例初始化塊 / 構造器構造器完成前必須賦值,且僅一次
靜態字段聲明處 / 靜態初始化塊類加載完成前必須賦值,且僅一次
局部變量首次賦值前使用前必須確定賦值(定賦分析),僅一次
方法參數調用時傳入方法體內不可重新賦值

實例字段初始化鏈

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 已賦值
    }
}

final 參數與匿名內部類/Lambda 捕獲

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();
}

2. final 方法:禁止覆寫

  • 子類不能覆寫(@Override 編譯錯誤)。
  • 編譯器可內聯優化(消除虛方法調用開銷),但現代 JIT 已自動內聯熱點方法,final 提示作用較小。
  • 常見用途:模板方法模式中骨架方法 public final void template() 防止子類破壞流程。

3. final 類:禁止繼承

  • 不能有子類(extends FinalClass 編譯錯誤)。
  • 類中所有方法隱式 final(字段不受影響)。
  • 典型類:String, Integer, LocalDate 等不可變類、工具類 Math, Collections。
  • 安全考量:防止惡意子類竄改行為(如 SecurityManager 相關)。

final 與不可變對象設計

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);
    }
}

final + static:編譯期常量(常量折疊)

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 關鍵字補充

native 方法:Java 聲明,實現由 C/C++ 等本地代碼在 JVM 內部完成(JNI)。

  • 無方法體,以分號結尾:public native void registerNatives();
  • 常見於系統級類:Object.registerNatives(), System.arraycopy(), Thread.start0(), Class.forName0()。
  • 性能關鍵路徑、操作系統交互、硬件訪問。
  • 調試困難、跨平台需編譯多份動態庫、安全風險(JNI 錯誤可崩潰 JVM)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved