Java 合法的前向引用

12

以下代码是否合法的前向引用?如果是,为什么?

public class MyClass
{
  private static int x = getValue();
  private static int y = 5;
  private static int getValue()
  {
    return y;
  }
  public static void main(String[] args)
  {
    System.out.println(x);
  }
}
2个回答

20

你目前所拥有的代码是完全合法的Java代码。在Java中,静态字段初始化如下:首先,所有字段都会设置为其类型的默认值(0、falsenull),然后按照声明顺序进行初始化。这意味着上述代码保证将执行以下操作:

  1. xy设置为0,因为这是int类型的默认值。
  2. 通过调用getValue()方法来初始化x,该方法读取y的值。由于y尚未初始化,因此它仍然具有值0。
  3. y初始化为5。

这意味着x将取值0,而y将取值5。这种行为是可移植且保证的。您可以在此处查看

希望对你有所帮助!


如果这些不是静态变量和方法,会是什么情况? - Vibhor
2
我相信行为是一样的 - 初始化首先将所有内容设置为默认值,然后使用指定的值初始化每个内容,最后调用构造函数。 - templatetypedef
1
顺便说一下,这就是为什么你永远不应该从构造函数中调用非最终(或私有)方法的原因之一;这太容易被某人覆盖了,看到一个尚未构建的 this,甚至可以看到一个未初始化的最终字段。 - yshavit
你的回答是否与下面的回答相矛盾,其中使用了 private static int x=y; private static int y=5; 会导致前向引用错误? - Neil Walker
Java允许您间接地使一个变量前向引用另一个变量,但不允许您直接使一个变量前向引用另一个变量。 OP的代码没有直接将x设置为y,因此没有错误。 但是,您是正确的,您的代码版本将会产生前向引用错误。 - templatetypedef

5

通过编译结果可以判断是否合法;与其他语言不同,Java没有“未定义行为”的概念。这里发生的一切都是明确规定的。这可能有些违反直觉,但它是合法的:在初始化另一个静态变量时调用方法可以访问尚未初始化的静态变量。直接从x的初始化器中访问y的表面上类似的情况不同。

private static int x = y;
private static int y = 5;

具体禁止使用此功能。没有强烈的理由 -- 这就是事实。


如果变量不是静态的,那么在这种情况下行为是否相同? - Vibhor
是的,它们实际上是相同的。静态变量的规则略有不同,因为类没有实际的“构造函数”,但对象的初始化方式基本相同。对于实例变量,初始化器和实例块按照出现的顺序前置到每个构造函数中。对于静态变量,初始化器和静态块按顺序编译成一个名为<clinit>()的单个方法。 - Ernest Friedman-Hill
拥有一个可以通过编译器进行测试的程序对于像这样的问题来说是一种奢侈品,我很抱歉。这是从OCJP考试的模拟考试中提取出来的。我现在正在学习它,而这些完全没有意义的愚蠢问题使考试的意图变得荒谬。 - Neil Walker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接