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

Java 为什么静态init块中的赋值编译时没有错误?,java,initialization,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 St

我在用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"
}
如您所见,我们无法引用尚未声明的字段,因此,
System.out.println(staticField)上出现编译错误

在定义字段之前,无法引用该字段

但是,可以指定这样一个字段,我们可以从第二个静态块中的值看出这一点


为什么会这样?

行为列在:

成员的声明需要以文本形式出现,然后才能被删除 仅当成员是的实例(分别为静态)字段时使用 类或接口C和以下所有条件均成立:

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

  • 用法不在作业的左侧

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

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

如果以上四个要求中的任何一个被忽略,则这是编译时错误 没有遇见

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

换句话说,您可以为这些字段分配任何值,但不能在简单名称上使用它们的值,这是您在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
}

我认为编译器在执行静态变量之前读取所有静态变量引用blocks@karim是的,但问题是,如果定义了变量,为什么在声明后不能使用它,但可以初始化?@karim Static fields初始化和Static init块按照Java文档的源代码顺序执行。但是,我没有发现关于声明本身的任何信息(与初始化相反)。无论如何,如果字段声明是以前读过的,那么为什么读访问是不可能的,而写访问是不可能的?关于在引用变量之前声明变量的规则实际上只适用于局部变量。@Hot-Licks那么为什么
System.out.println(staticField)上有编译错误?我明白了。但奇怪的是,在类中声明字段时,我们需要一个完全限定的名称。@Joffrey有些东西是我们无法推理的,原因很简单,因为语言就是这样设计的。我不是评论这是否正确的合适人选。乍一看可能有点奇怪,但你会习惯这些规则的。他们太多了。幸运的是,您几乎总能在JLS中找到原因:)是的,没错^^我想有一些原因可以简化编译器。无论如何,谢谢你的回答!