【问题标题】:which variable is being accessed, local or class level?正在访问哪个变量,本地或类级别?
【发布时间】:2016-11-21 09:27:04
【问题描述】:

考虑Lambda Expressions 中给出的以下代码:

import java.util.function.Consumer;

public class LambdaScopeTest {

    public int x = 0;

    class FirstLevel {

        public int x = 1;

        void methodInFirstLevel(int x) {

            // The following statement causes the compiler to generate
            // the error "local variables referenced from a lambda expression
            // must be final or effectively final" in statement A:
            //
            // x = 99;

            Consumer<Integer> myConsumer = (y) -> 
            {
                System.out.println("x = " + x); // Statement A
                System.out.println("y = " + y);
                System.out.println("this.x = " + this.x);
                System.out.println("LambdaScopeTest.this.x = " +
                    LambdaScopeTest.this.x);
            };

            myConsumer.accept(x);

        }
    }

    public static void main(String... args) {
        LambdaScopeTest st = new LambdaScopeTest();
        LambdaScopeTest.FirstLevel fl = st.new FirstLevel();
        fl.methodInFirstLevel(23);
    }
}

在 JavaDocs 中写道:

假设您立即添加以下赋值语句 在methodInFirstLevel 定义语句之后:

 void methodInFirstLevel(int x) {
     x = 99;
     // ... }

由于这个赋值语句,变量FirstLevel.x 不再是有效的final。结果,Java 编译器生成类似于“局部变量”的错误消息 从 lambda 表达式引用必须是最终的或有效的 final”,其中 lambda 表达式 myConsumer 尝试访问 FirstLevel.x变量:

System.out.println("x = " + x);

我无法理解 System.out.println("x = " + x)(语句 A)如何访问 FirstLevel.x?不应该是methodInFirstLevel(int x)方法中传入的x吗?

【问题讨论】:

  • 我认为这意味着 lambda 表达式无法访问 x 中的 x 参数,因为它实际上不是最终的。它的措辞可能令人困惑(或实际上是错误的)。
  • 编译器不知道,你在myConsumer.accept(x);做什么,所以它假设x可以在这个方法中改变,如果是它就不能是最终的。这就是你得到错误的原因。
  • @TEXHIK,由于 Java 是按值传递的,myConsumer 不能更改 x。这不是问题。
  • 这似乎是教程中的错误。更有意义的是它说“由于这个赋值语句,参数x 不再是有效的最终参数。 ”

标签: java lambda scope


【解决方案1】:

这似乎是教程中的错误。我认为该段应为:

因为这个赋值语句,参数x不是 有效地最终了。结果,Java 编译器生成一个 类似于“从 lambda 引用的局部变量”的错误消息 表达式必须是最终的或有效的最终”,其中 lambda 表达式 myConsumer 尝试访问 x 参数:

System.out.println("x = " + x);

我的论点基于两个观察结果:引用的错误消息说“局部变量”,它可能包括参数,但不包括字段。引用的 print 语句打印 23,这是参数的值,而不是 FirstLevel.x 的值。

【讨论】:

    【解决方案2】:

    总是:如果你在方法中有任何局部变量,那么 Java 会首先选择局部变量,然后类原因是局部变量的范围非常有限,并且类变量可以在类的所有方法中访问

    【讨论】:

      【解决方案3】:

      Java 总是使用给定名称的最内层变量。

      这导致了这个层次结构(降序):

      • 方法局部变量
      • 类变量/字段
      • 父类变量/字段
      • 包装类变量/字段

      除非您明确使用this.varClass.var 对其进行限定。

      【讨论】:

        猜你喜欢
        • 2019-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-04-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-13
        相关资源
        最近更新 更多