当我添加“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时。