gpt4 book ai didi

java - 使用未初始化的最终字段 - 带/不带 'this.' 限定符

转载 作者:太空宇宙 更新时间:2023-11-04 12:07:48 25 4
gpt4 key购买 nike

有人可以向我解释为什么以下两个示例中的第一个可以编译,而第二个则不能编译?请注意,唯一的区别是第一个用“.this”显式限定对 x 的引用,而第二个则没有。在这两种情况下,最终字段 x 显然是在初始化之前尝试使用的。

我本以为这两个样本会被完全平等地对待,从而导致两者都出现编译错误。

1)

public class Foo {
private final int x;
private Foo() {
int y = 2 * this.x;
x = 5;
}
}

2)

public class Foo {
private final int x;
private Foo() {
int y = 2 * x;
x = 5;
}
}

最佳答案

经过大量规范阅读和思考后,我得出的结论是:

在 Java 5 或 Java 6 编译器中,这是正确的行为。 Chapter 16 "Definite Assignment of The Java Language Specification, Third Edition说:

Each local variable (§14.4) and every blank final (§4.12.4) field (§8.3.1.2) must have a definitely assigned value when any access of its value occurs. An access to its value consists of the simple name of the variable occurring anywhere in an expression except as the left-hand operand of the simple assignment operator =.

(强调我的)。所以在表达式 2 * this.x 中,this.x部分被视为“访问[x的]值”(因此不受明确赋值的规则的约束),因为this.x不是实例变量 x 的简单名称。 (注意,在上述引用文本后面的段落中,发生明确赋值时的规则确实允许类似 this.x = 3 的内容,并认为 x 此后被明确赋值;这只是不计算 this.x 的访问规则。)请注意 this.x 的值。在这种情况下将为零,根据 §17.5.2 .

在 Java 7 编译器中,这是一个编译器错误,但可以理解。 Chapter 16 "Definite Assignment" of the Java Language Specification, Java 7 SE Edition说:

Each local variable (§14.4) and every blank final field (§4.12.4, §8.3.1.2) must have a definitely assigned value when any access of its value occurs.

An access to its value consists of the simple name of the variable (or, for a field, the simple name of the field qualified by this) occurring anywhere in an expression except as the left-hand operand of the simple assignment operator = (§15.26.1).

(强调我的)。所以在表达式 2 * this.x 中,this.x部分应该被视为“访问[x的]值”,并且应该给出编译错误。

但是您没有问第一个是否应该编译,而是问为什么确实编译(在某些编译器中)。这必然是推测,但我会做出两个猜测:

  1. 大多数 Java 7 编译器都是通过修改 Java 6 编译器编写的。一些编译器编写者可能没有注意到这一变化。此外,许多 Java-7 编译器和 IDE 仍然支持 Java 6,并且一些编译器编写者可能没有动力专门拒绝 Java-7 模式中他们在 Java-6 模式中接受的某些内容。
  2. 新的 Java 7 行为奇怪地不一致。类似 (false ? null : this).x仍然允许,就此而言,甚至 (this).x仍然允许;这只是特定的 token 序列 this.加上受此更改影响的字段名称。诚然,这种不一致已经存在于赋值语句的左侧(我们可以写 this.x = 3 ,但不能写 (this).x = 3 ),但这更容易理解:它接受 this.x = 3 。作为其他禁止建筑的特殊允许情况obj.x = 3 。允许这样做是有道理的。但我认为拒绝2 * this.x没有意义。作为其他允许的建筑的特殊禁止情况2 * obj.x ,鉴于 (1) 这种特殊禁止的情况可以通过添加括号轻松解决,(2) 这种特殊禁止的情况在该语言的早期版本中是允许的,并且 (3) 我们仍然需要特殊规则,其中 final字段在初始化之前都有默认值(例如 0 表示 int ),这都是因为像 (this).x 这样的情况,并且由于像 this.foo() 这样的情况哪里foo()是访问 x 的方法。因此,一些编译器编写者可能没有动力做出这种不一致的更改。

其中任何一个都会令人惊讶 - 我认为编译器编写者拥有有关规范的每一个更改的详细信息,并且根据我的经验,Java 编译器通常非常善于严格遵守规范(与某些语言不同,每个编译器都有自己的方言) - 但是,发生了一些事情,以上是我仅有的两个猜测。

关于java - 使用未初始化的最终字段 - 带/不带 'this.' 限定符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40191673/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com