最终变量首先初始化

final variable initialized first

我正在阅读这里的问题:Java : in what order are static final fields initialized?

根据回答

"except that final class variables and fields of interfaces whose values are compile-time constants are initialized first ..."

我认为这是不正确的,因为以下会失败:

static {
    String y = x;
}

public static final String x = "test";

在静态块中,x不被识别。如果答案正确,有人可以发表评论吗?

this answer所述:

... they are initialized in the order in which they appear in the source.

你完全正确,你的例子失败了,因为你试图使用一个在使用之后声明的变量。由于静态块是按源代码的顺序执行的,因此您是绝对正确的,应该建议并编辑该答案,因为此语句无效:

except that final class variables ... are initialized first.

初始化 的顺序不会改变 JLS 不允许您在各种情况下声明变量之前引用变量的事实。这在 JLS§8.3.3:

中有描述

Use of class variables whose declarations appear textually after the use is sometimes restricted, even though these class variables are in scope (§6.3). Specifically, it is a compile-time error if all of the following are true:

  • The declaration of a class variable in a class or interface C appears textually after a use of the class variable;

  • The use is a simple name in either a class variable initializer of C or a static initializer of C;

  • The use is not on the left hand side of an assignment;

  • C is the innermost class or interface enclosing the use.

这就是您的代码出现此编译错误的原因:

error: illegal forward reference

作为常量变量的静态字段先初始化的说法确实在JLS§12.4.2中定义:

  1. Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC.

    Then, initialize the static fields of C which are constant variables (§4.12.4, §8.3.2, §9.3.1).

...

  1. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.

如您所见,常量变量在第 6 步初始化,而其他变量在第 9 步初始化。

这演示了行为:

public class Example {
    static String y;
    static  {
         y = foo();
    }

    static String foo() {
        return x.toUpperCase();
    }

    public static final String x = "test";

    public static void main(String[] args) throws Exception {
        System.out.println(x);
        System.out.println(y);
    }
}

编译并输出:

test
TEST

相比之下,如果您更改 x 行使其不再恒定:

public static final String x = Math.random() < 0.5 ? "test" : "ing";

编译成功,但随后失败,因为 xy = foo(); 时是 null


为免生疑问:我建议使用方法来初始化这样的字段。 :-)