当我添加“this”时,recursion初始化器工作吗?

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

 class test { int x = x + 42; } 

但是这个工作:

 class test { int x = this.x + 42; } 

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

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

行为符合JLS,特别是§8.3.2.3。 在初始化过程中限制使用字段

成员声明只有在成员是类或接口C的实例(分别是static )字段并且以下所有条件成立时,才需要以文本forms出现:

  • 用法发生在C的一个实例(分别是static )variables初始值设定项或C中的一个实例(分别是static )初始值设定项中。

  • 用法不在作业的左侧。

  • 用法是通过一个简单的名字。

  • C是封闭用法的最里面的类或接口。

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

事件的总体顺序如下:

  • 当一个类的实例被创build时,所有的字段都被初始化为它们types的默认值。
  • 然后初始化器按文本顺序 (从上到下)运行。

因此,如果初始化器引用稍后在类定义(或字段本身)中出现的字段,则会看到该字段的默认值。 这很可能是编程错误,因此第8.3.2.3节明确禁止。

例如,如果你通过使用this.来规避§8.3.2.3 this. 要转发指向一个字段, 你会看到默认值 ( int为零)。 因此,以下是明确的,并保证将x设置为42

 class test { int x = this.x + 42; } 

在x的初始化过程中发现和禁止所有对x访问是非常困难的。 例如

 int x = that().x; | int x = getX(); | Test that(){ return this; } | int getX(){ return x; } 

规范停止在“简单名称访问”,并没有试图更全面。

在另一部分,“明确的任务”,规范做类似的事情。 例如

 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; } } 

有趣的是,“明确赋值”特别提到this.x等价于x

(或者,对于一个字段来说,这个字段的简单名字就是合格的)

这个条款也可以添加到NPE引用的部分。

  • 用法是通过一个简单的名字(或一个简单的名字)

但是最终,在编译时不可能分析所有可能的对某一领域的使用/访问。

在第一种情况下,编译器试图计算expression式“x + 42”,但是因为x没有被初始化而失败。

在第二种情况下,expression式“this.x + 42”在运行时被计算(因为“this”关键字),当x已经被初始化并且值为0时。