当从匿名内部类或 lambda 访问时,为什么数组的值被视为最终或“有效最终”?

Spa*_*jjm 0 java java-8

我正在阅读有关函数式接口(https://www.baeldung.com/java-8-function-interfaces)的内容,并且关于 a Supplier<T>,它是这样说的:

\n\n
\n

供应商的另一个用例是定义序列生成的逻辑。为了演示它,让\xe2\x80\x99s 使用静态 Stream.generate 方法来创建斐波那契数字流:

\n
\n\n
int[] fibs = {0, 1};\nStream<Integer> fibonacci = Stream.generate(() -> {\n    int result = fibs[1];\n    int fib3 = fibs[0] + fibs[1];\n    fibs[0] = fibs[1];\n    fibs[1] = fib3;\n    return result;\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n

传递给 Stream.generate 方法的函数实现了Supplier 功能接口。请注意,要用作生成器,供应商通常需要某种外部状态。在这种情况下,其状态由最后两个斐波那契数列组成。

\n\n

为了实现这种状态,我们使用一个数组而不是几个变量,因为 lambda 内部使用的所有外部变量实际上都是 Final

\n
\n\n

我理解为什么变量在 lamdba 或匿名类中需要是最终的,我不明白的是为什么数组的值是“有效的最终”。

\n\n

我用下面的例子来说明这一点:

\n\n
final boolean run = true;\nexecutor.execute(() -> {\n    while (run) {\n        // do something\n    }\n});\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里run是final的,所以定义lamdba后就不能修改了。这对我来说很有意义。

\n\n
boolean[] runArr = { true };\nexecutor.execute(() -> {\n    while (run) {\n        // do something\n    }\n});\nrunArr[0] = false;\n
Run Code Online (Sandbox Code Playgroud)\n\n

run不是最终的,因为我可以修改 的内容runArr[0]。这似乎可能会产生意外的行为,并可能导致并发问题。我的问题是,为什么编译器允许你这样做?这不是违反了final only变量的规则吗?

\n

lar*_*fer 5

存储在数组中的值不是(实际上)最终的(并且它们不需要)

然而,对数组本身的引用实际上是最终的。

对于“正常”(原始)变量,该变量在技术上保存实际值。对于数组(和对象),变量在技术上保存一个指向数组第一个元素(或对象数据的开头)的指针。因此,当在 lambda 表达式中使用数组时,变量(指向数组的指针)实际上是最终变量,但数组的内容(指针指向的位置)仍然可以更改。