【发布时间】:2018-08-28 04:30:51
【问题描述】:
首先,一个谜题: 下面的代码打印什么?
public class RecursiveStatic {
public static void main(String[] args) {
System.out.println(scale(5));
}
private static final long X = scale(10);
private static long scale(long value) {
return X * value;
}
}
答案:
0
以下剧透。
如果您按比例(长)打印X 并重新定义X = scale(10) + 3,
打印件将是X = 0,然后是X = 3。
这意味着X 暂时设置为0,之后又设置为3。
这违反了final!
static修饰符与final修饰符结合,也用于定义常量。 final修饰符表示该字段的值不能改变。
来源:https://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html [强调添加]
我的问题:
这是一个错误吗?
final 定义不明确吗?
这是我感兴趣的代码。
X 被分配了两个不同的值:0 和 3。
我认为这违反了final。
public class RecursiveStatic {
public static void main(String[] args) {
System.out.println(scale(5));
}
private static final long X = scale(10) + 3;
private static long scale(long value) {
System.out.println("X = " + X);
return X * value;
}
}
此问题已被标记为可能与 Java static final field initialization order 重复。
我相信这个问题不是重复的,因为
另一个问题解决了初始化的顺序,而
我的问题解决了与final 标签相结合的循环初始化。
仅从另一个问题,我无法理解为什么我的问题中的代码不会出错。
通过查看 ernesto 获得的输出,这一点尤其明显:
当a 被标记为final 时,他得到以下输出:
a=5
a=5
这不涉及我问题的主要部分:final 变量如何更改其变量?
【问题讨论】:
-
这种引用
X成员的方式就像在超类构造函数完成之前引用子类成员,这是你的问题,而不是final的定义。 -
来自 JLS:
A blank final instance variable must be definitely assigned (§16.9) at the end of every constructor (§8.8) of the class in which it is declared; otherwise a compile-time error occurs. -
@Ivan,这不是关于常量,而是关于实例变量。但是你可以添加章节吗?
-
请注意:切勿在生产代码中执行任何此类操作。如果有人开始利用 JLS 中的漏洞,每个人都会感到非常困惑。
-
仅供参考,您也可以在 C# 中创建完全相同的情况。 C# 承诺 constant 声明中的循环将在编译时被捕获,但没有对 readonly 声明做出这样的承诺,实际上您可能会遇到初始零值的情况由另一个字段初始化器观察到该字段。如果这样做时会感到疼痛,不要这样做。编译器不会救你的。
标签: java final class-variables static-initialization