为什么静态init块中的赋值编译没有错误?

Jof*_*rey 5 java initialization

我正在尝试Java中的初始化顺序,我遇到了一些令人困惑的事情:

static {
    System.out.println("Static 1, staticField can't be accessed (compile error)");
    staticField = "value"; // NO COMPILE ERROR!
    //System.out.println(staticField); // compile error
}

public static String staticField;

static {
    System.out.println("Static 2, staticField=" + staticField); // prints "value"
}
Run Code Online (Sandbox Code Playgroud)

如您所见,我们无法引用尚未声明的字段,因此System.out.println(staticField);第一个静态块中的编译错误:

在定义之前无法引用字段.

然而,也可以分配这样一个领域,我们可以从第二静态块的价值出来.

为什么会这样?

Roh*_*ain 4

JLS §8.3.2.3 - 初始化期间使用字段的限制中列出了该行为:

仅当成员是类或接口 C 的实例(分别是静态)字段并且满足以下所有条件时,成员的声明才需要在使用之前以文本形式出现:

  • 该用法发生在 C 的实例(分别为静态)变量初始值设定项或 C 的实例(分别为静态)初始值设定项中。

  • 用法不在赋值的左侧。

  • 用法是通过一个简单的名称。

  • C 是包含用法的最内部类或接口。

如果不满足上述四个要求中的任何一个,则会出现编译时错误。

static基本上,当您通过表达式左侧的简单名称访问字段时,根据第二条规则,不应在其之前进行声明。但是,如果在赋值的右侧使用它,或者尝试在表达式中使用它的值,则需要事先声明它,否则会出现编译器错误。

换句话说,您可以为这些字段分配任何值,但不能在简单名称上使用它们的值,而这正是您在 print 语句中尝试执行的操作。

当然,如果您使用限定名称的字段,那么它就可以工作。因此,以下代码将编译:

static {
    System.out.println("Static 1, staticField can't be accessed (compile error)");
    staticField = "value"; // NO COMPILE ERROR!
    System.out.println(Main.staticField); // compiles fine now
}
Run Code Online (Sandbox Code Playgroud)