在 Java 开发中,使用 Lambda 表达式或匿名内部类时,我们常会遇到一个限制:访问的外部局部变量必须是 final 或等效 final。这看似简单的语法规则,实则关乎 JVM 内存模型与线程安全的底层设计。
什么是匿名内部类
匿名内部类是没有显式名称的内部类,通常用于创建只使用一次的实例。比如事件监听器:
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button clicked!");
}
});
final 限制的历史演变
Java 8 之前的严格 final
在 Java 8 之前,规范强制要求任何被匿名内部类访问的外部方法参数或局部变量都必须显式声明为 final。
// Java 7 及之前版本
public void process(String message) {
final String finalMessage = message; // 必须声明为 final
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(finalMessage); // 访问外部变量
}
}).start();
}
Java 8 的等效 final(effectively final)
Java 8 引入了一个改进概念:如果一个变量初始化后没有被重新赋值,即使没有显式声明 final,编译器也会将其视为 final,这就是'等效 final'。
// Java 8 及之后版本
public void process(String message) {
// message 是等效 final 的,因为它没有被重新赋值
new Thread( () {
{
System.out.println(message);
}
}).start();
}


