Ja va 局部内部类想要访问外层方法的局部变量,有个硬性要求:这些变量必须是 有效 final(effectively final)。简单说,就是变量虽然没有显式加上 final 关键字,但从初始化之后,就再也不能被修改了。

为什么必须是 effectively final?

这背后涉及到 JVM 的内存模型。局部变量是存储在方法栈帧里的,方法执行完,栈帧销毁,变量也就没了。但局部内部类的对象可能活得更久——比如被返回出去或者被其他线程引用。这时候内部类要访问那个已经“消失”的变量怎么办?JVM 的做法是:在创建内部类对象时,把变量的值复制一份,存在内部类自己的实例里。为了保证内外数据一致,就得保证这个值在复制之后不会变。所以,干脆要求变量不可变,从根本上避免不一致的问题。

如何满足 effectively final?

常见错误示例

下面这种写法,编译直接报错:

void method() {
    String s = "hello";
    s = "world"; // 修改了,不再是 effectively final
    class Local { void print() { System.out.println(s); } } // 编译失败
}

而这样写,就完全没问题:

void method() {
    String s = "hello"; // 没再改过
    class Local { void print() { System.out.println(s); } } // 编译通过
}

小技巧:调试是否 effectively final

如果拿不准某个变量是不是 effectively final,有个简单粗暴的办法:给它加上 final 关键字试试。如果编译通过,说明它本来就是 effectively final;如果编译器报错“无法为 final 变量赋值”,那就说明你之前确实修改过它,需要调整逻辑。

本文转载于:https://www.php.cn/faq/2814817.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。