Java中用Lambda实现接口时,数组为何可突破变量访问限制?
核心原因:Lambda的变量捕获规则
Java里Lambda表达式捕获局部变量时,要求变量必须是final或者等效final(effectively final)——简单说就是变量初始化后,再也没有被重新赋值过。
普通boolean变量为什么不行?
如果用普通boolean hasMoney,你在Lambda里给它赋值(比如hasMoney = true),相当于修改了这个变量本身,它就不再是等效final的了。编译器会直接报错,因为Lambda可能在原方法的栈帧销毁后才执行(比如异步场景),此时普通局部变量已经不存在了,Java通过强制变量不可变来避免这种"变量失效"的问题。
数组为什么能行?
数组是引用类型:你定义的boolean[] hasMoney = new boolean[1],hasMoney这个变量存的是数组对象的内存地址。在Lambda里你修改的是hasMoney[0]——也就是数组内部的元素,而hasMoney本身的引用(指向的内存地址)从始至终都没改变过,完全符合"等效final"的要求。编译器允许这种操作,因为数组对象本身是在堆上的,即使原方法栈帧销毁,数组对象依然存在,Lambda可以安全地修改它的元素。
额外补充:除了数组还有其他方案吗?
当然,你也可以用Java提供的原子类比如AtomicBoolean,原理和数组一样——变量引用本身不变,修改的是类内部的可变值,同样符合Lambda的捕获规则。
结合你的代码看
你的代码里,hasMoney数组的引用从未被重新赋值,只是修改了下标0的元素值,所以编译器放行;如果换成普通boolean变量,在Lambda里赋值会直接触发编译错误,因为变量不再是等效final的。
内容的提问来源于stack exchange,提问作者Tobi Cinquante

