当前位置: 首页 > 知识库问答 >
问题:

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

殷德本
2023-03-14
int[] fibs = {0, 1};
Stream<Integer> fibonacci = Stream.generate(() -> {
    int result = fibs[1];
    int fib3 = fibs[0] + fibs[1];
    fibs[0] = fibs[1];
    fibs[1] = fib3;
    return result;
});

传递给Stream.Generate方法的函数实现了供应商功能接口。注意,要作为生成器有用,供应商通常需要某种外部状态。在本例中,它的状态由两个最后的斐波那契序列号组成。

为了实现这种状态,我们使用一个数组而不是两个变量,因为lambda内部使用的所有外部变量都必须是final的。

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

final boolean run = true;
executor.execute(() -> {
    while (run) {
        // do something
    }
});

在这里,run是最终的,因此在定义LAMDBA之后不能修改它。这对我来说是有道理的。

boolean[] runArr = { true };
executor.execute(() -> {
    while (run) {
        // do something
    }
});
runArr[0] = false;

在这里,run不是最终的,因为允许我修改runarr[0]的内容。这似乎会产生意想不到的行为,并可能导致并发问题。我的问题是,编译器为什么允许你这样做?这不是打破了最终唯一变量的规则吗?

共有1个答案

仲孙经赋
2023-03-14

存储在数组中的值(实际上)不是final(也不需要是final)

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

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

 类似资料:
  • 问题内容: 在这里只能是最终的。为什么?如何在不保留为私有成员的情况下重新分配方法? 单击该如何返回? 问题答案: 如注释中所述,其中一些在Java 8中变得无关紧要,在Java 8中final可以隐式使用。但是,只能在匿名内部类或lambda表达式中使用有效的最终变量。 这基本上是由于Java管理闭包的方式。 创建匿名内部类的实例时,该类中使用的任何变量都将通过自动生成的构造函数复制其值。这样避

  • 问题内容: 根据JLS: 15.9.5匿名类声明编译器会自动从类实例创建表达式派生匿名类声明。 匿名类从不抽象(第8.1.1.1节)。匿名类始终是内部类(第8.1.3节);它永远不是静态的(第8.1.1节,第8.5.2节)。 匿名类始终是隐式最终的(第8.1.1.2节) 。 这似乎是一个特定的设计决定,所以它有一定的历史。 如果我选择上这样的课: 如果选择的话,为什么不允许我再次对其进行子类化?

  • 下面的表达没有问题- 但以下两个有编译时间问题- 为什么呢?

  • 下面的表达没有问题- 但下面两个有编译时问题- 为什么呢?

  • 问题内容: 就在今天,我需要一种在不同对象之间传递函数的方法。我很快了解到您不能直接在Java中做到这一点,但是您可以传递一个wht实例,该实例显然被称为“匿名内部类”,如下所示: 定义类: 使其成为一个实例: 并称之为: 很简单。但是我不明白的是为什么它被称为“匿名”。我不只是给它起名字MyCallback吗?命名的东西不能匿名,对吗?请避免对这个术语感到困惑。 问题答案: 不,您说的是MyCa

  • 我正在尝试返回对象。 但我得到了 从内部类引用的局部变量必须是最终变量或实际上是最终变量 on < code > stats = statistics如何返回对象,但要确保< code >。close();是否正在运行?