區域變數存放在堆疊框架中,隨方法結束而銷毀;但區域內部類的實例可能在方法返回後長期存活(例如被傳遞到其他執行緒、存放在集合中)。若內部類直接引用堆疊上的區域變數,方法結束後該記憶體已失效,存取將導致未定義行為。
final(Java 8 後支援「effectively final」,即僅賦值一次的變數)。void process() {
final int localVar = 42; // 或 Java 8+ 不加 final 但只賦值一次
Runnable r = new Runnable() {
@Override public void run() {
System.out.println(localVar); // 實際讀取的是內部類合成欄位 copyOfLocalVar
}
};
new Thread(r).start(); // 方法結束後 localVar 消失,但 r 仍持有 copyOfLocalVar = 42
}
Lambda 表達式同樣捕獲區域變數,規則相同:變數必須是 final 或 effectively final。但 Lambda 不會產生獨立的類別檔案,由 invokedynamic 指令在執行期動態生成實例,效能更好。
final 限制本質上是為了語義安全:確保內部類看到的變數值在其生命週期內不可變,避免「變數已消失但內部類仍持有引用」的危險。這是 Java 在編譯期以靜態分析換取執行期安全的經典設計權衡。