当我添加"this"时,递归初始化程序是否有效?

nne*_*neo 35 java

无法编译(有illegal forward reference错误),正如人们所期望的那样:

class test {
    int x = x + 42;
}
Run Code Online (Sandbox Code Playgroud)

但这有效:

class test {
    int x = this.x + 42;
}
Run Code Online (Sandbox Code Playgroud)

这是怎么回事?在后一种情况下分配了什么?

Zho*_*gYu 18

x在x初始化期间发现并禁止所有访问都太困难了.例如

int x = that().x;                |    int x = getX();
                                 |
Test that(){ return this; }      |    int getX(){ return x; }
Run Code Online (Sandbox Code Playgroud)

规范在"通过简单名称访问"时停止,并且不会尝试更全面.

在另一节"定义分配"中,规范做了类似的事情.例如

public class Test
{
    static final int y;
    static final int z = y;  // fail, y is not definitely assigned 
    static{ y = 1; }
}

public class Test
{
    static final int y;
    static final int z = Test.y;  // pass... because it's not a simple name
    static{ y = 1; }
}
Run Code Online (Sandbox Code Playgroud)

有趣的是,"Definite Assignment"特别提到了this.x相当于x

(或者,对于字段,由此限定的字段的简单名称)

该条款也可以添加到NPE引用的部分.

  • 用法是通过简单的名称(或由此限定的简单名称)

但最终,在编译时不可能分析对字段的所有可能的使用/访问.


NPE*_*NPE 17

简介:两个初始值设定项都访问尚未初始化的字段(因此仍然具有默认值零).由于这可能是编程错误,因此该语言禁止这种访问的一些简单形式.但是,它并没有禁止更复杂的形式.

该行为符合JLS,特别是§8.3.2.3.初始化期间使用字段的限制

成员声明只有在成员是static类或接口的实例(分别)字段C并且满足以下所有条件时才需要以文本方式显示:

  • 用法发生在C的实例(分别static)变量初始化器或C的实例(分别static)初始化器中.

  • 用法不在作业的左侧.

  • 用法是通过一个简单的名称.

  • C 是封闭用法的最内层的类或接口.

第一个示例满足所有四个条件,因此无效.第二个例子不满足第三个条件(this.x不是一个简单的名字),因此可以.

事件的整体顺序如下:

因此,如果初始化程序引用稍后出现在类定义中(或字段本身)的字段,则它将看到该其他字段的默认值.这可能是编程错误,因此§8.3.2.3明确禁止.

如果您绕过§8.3.2.3,例如,使用this.向前引用字段,您将看到默认值(零为int).因此,以下内容定义明确,并保证设置x42:

class test {
    int x = this.x + 42;
}
Run Code Online (Sandbox Code Playgroud)