java使用带/不带“this”的未初始化最终字段合格者
有人能给我解释一下为什么下面两个示例中的第一个可以编译,而第二个不能编译?请注意,唯一的区别是,第一个显式地将对x的引用限定为'。这是',而第二个不是。在这两种情况下,在初始化之前显然尝试使用最终字段x
我本以为这两个样本会被完全平等地对待,从而导致两者的编译错误
(一)
public class Foo {
private final int x;
private Foo() {
int y = 2 * this.x;
x = 5;
}
}
(二)
public class Foo {
private final int x;
private Foo() {
int y = 2 * x;
x = 5;
}
}
# 1 楼答案
经过一系列的规范阅读和思考,我得出结论:
在Java5或Java6编译器中,这是正确的行为Chapter 16 "Definite Assignment of The Java Language Specification, Third Edition说:
(我的重点)。因此,在表达式
2 * this.x
中,this.x
部分被认为不是“对[x
值的访问”(因此不受明确赋值规则的约束),因为this.x
不是实例变量x
的简单名称。(注意:在上面引用的文本后面的段落中,允许像this.x = 3
这样的东西,并且认为x
在此后被明确分配;这只是不计算this.x
的访问规则。)注意,在这种情况下,this.x
的值将为零,每§17.5.2在Java7编译器中,这是一个编译器错误,但可以理解Chapter 16 "Definite Assignment" of the Java Language Specification, Java 7 SE Edition说:
(我的重点)。因此,在表达式
2 * this.x
中,this.x
部分应被视为“访问[x
的]值”,并且应给出编译错误但是你没有问第一个是否应该编译,而是问为什么它会编译(在某些编译器中)。这必然是推测,但我要做两个猜测:
(false ? null : this).x
的东西仍然是允许的,就这一点而言,甚至(this).x
仍然是允许的;受此更改影响的只有特定的令牌序列this
加上.
加上字段名。诚然,在赋值语句的左侧已经存在这样的不一致性(我们可以写this.x = 3
,但不能写(this).x = 3
),但这更容易理解:它接受this.x = 3
作为一种特殊的被禁止的构造obj.x = 3
。允许这样做是有道理的。但是我不认为把{final
字段在初始化之前都有它们的默认值(例如int
的0
),这两种情况都是因为(this).x
和this.foo()
这样的情况,其中foo()
是访问x
的方法。因此,一些编译器编写人员可能没有动机进行这种不一致的更改李>其中任何一种都是令人惊讶的——我假设编译器编写者对规范的每一次更改都有详细的信息,根据我的经验,Java编译器通常非常擅长严格遵守规范(不像某些语言,每个编译器都有自己的方言)——但是,嗯,发生了一些事情,以上是我仅有的两个猜测
# 2 楼答案
我想编译器估计写这篇文章会很困难。x表示“this”存在,因此调用了构造函数(并且初始化了最终变量)。 但是当您尝试运行它时,应该得到一个RuntimeException
# 3 楼答案
我想您指的是Eclipse中的行为。(如注释所述,使用javacworks编译)
我认为这是一个日食问题。它有自己的编译器和自己的规则集。其中之一是您可能无法访问未初始化的字段,尽管Java commpiler会为您初始化变量
# 4 楼答案
在构造函数中使用
this
时,编译器将x
视为this
对象(默认初始化)的成员属性。由于x
是int
,因此它默认使用0
初始化。这使编译器很高兴,并且在运行时也能正常工作当您不使用
this
时,编译器直接在词法分析中使用x
声明,因此它会抱怨它的初始化(编译时现象)所以它是
this
的定义,它使得编译器在编译过程中的词法分析过程中将x
作为对象的成员变量与直接属性进行分析,从而导致不同的编译行为