Java 在定义字段之前无法引用该字段,但仅当您不';我没有资格

Java 在定义字段之前无法引用该字段,但仅当您不';我没有资格,java,initialization,syntax-error,Java,Initialization,Syntax Error,我发现以下代码的出现让我大吃一惊: public class MCVE { { // instance initializer System.out.println(test); // cannot reference a field before it is defined System.out.println(this.test); } private final String test = "wat"; } 行

我发现以下代码的出现让我大吃一惊:

public class MCVE {

    { // instance initializer
        System.out.println(test); // cannot reference a field before it is defined
        System.out.println(this.test);
    }
    private final String test = "wat";
}
System.out.println(测试)正在给出错误

在定义字段之前无法引用该字段

但是行
System.out.println(this.test)不是


为什么在我对其进行限定时这不会出错?因为在创建lambda时可以捕获
。捕获
测试
未定义(尚未定义)。不过,稍后,在lambda中,您可以访问
测试
(通过
)。

与这些问题一样,这是因为

8.3.2.3初始化期间对字段使用的限制 仅当成员是类或接口C的实例(分别为
静态
)字段且满足以下所有条件时,成员声明才需要在使用前以文本形式出现:

  • 该用法出现在C的实例(分别为
    static
    )变量初始值设定项或C的实例(分别为
    static
    )初始值设定项中
  • 用法不在作业的左侧
  • 用法是通过一个简单的名称
  • C是包含用法的最内层类或接口
如果上述四项要求中的任何一项未得到满足,则为编译时错误。

在您的(失败的)示例中,“简单名称”案例是未满足的条件。限定用法(使用
this
)是解决编译时错误的漏洞

初始化块中声明字段的行之前的字段只能在表达式(即赋值)的左侧使用,除非它们是限定的(在您的示例中是
this.test


(为了更贴切地适应这个问题而进行解释)

这个问题不是lambdas特有的,实例初始值设定项也会有同样的问题。但是,普通构造函数不会有此问题。您可以将
private final Runnable r=()->{
更改为
{
,并将面临相同的行为。没有涉及构造函数…您想说明什么?您还可以将Runnable lambda更改为字符串字段:
private final String test2=test;
生成相同的结果(<代码> String Test2=这个测试。 Works)“仍然有点困惑:它会打印“WAT”还是“”,以防我们删除不合格行并运行lambda?我看到,正如Matt指出的。我猜我对C++是如何做的感到困惑,它让您控制这个或测试是否会被捕获(通过值等)。。lambda似乎与此无关。当在lambda之前创建一个新字段时,以合格的方式访问测试也会起作用。不,创建lambda会导致在创建时捕获。我不认为字段在这方面很重要。在最终和成员初始化中有严格的顺序。lambda应该捕获
this
在这两种情况下(假设另一种有效,可以通过将声明移到lambda之前获得)。正如在关于这个问题的两条评论中所指出的:这个问题不是lambdas特有的。我想我误解了Lambda捕获,我假设它是捕获时的值捕获,而不是通过
这个
。我同意这就是非限定实例不起作用的原因,但限定实例起作用的原因是不正确的。这不是一个循环le,但它根本不是在初始化期间访问测试。@ChristophenRoezbek限定引用特别有效,因为JLS这么说。它将如何工作?它将访问什么值?@ChristophenRoezbek java不是一种解释语言。我不得不说,它是在初始化期间访问的,因为这是一个小规范al,将“简单名称”转换为“限定名称”,因此不属于您在此处尝试的访问规则。@Christopher Roezbek只有一个可能的答案。