前向引用规则在JLS§8.3.3中定义:
有时会限制使用声明后在文本上出现的类变量,即使这些类变量在范围内(第6.3节)。具体来说,如果满足以下所有条件,则是编译时错误:
使用类变量后,将在文本或类C中声明类变量;
在C的类变量初始值设定项或C的静态初始值设定项中,此名称是一个简单的名称;
用法不在作业的左侧;
C是封闭使用的最里面的类或接口。
因此,基本上,您的first
Sysout()满足以上所有四个条件,因此是编译时错误。
在2nd中
Sysout(),您将
a使用它的限定名称(而不是简单名称)进行访问,根据上面的规则,该名称是允许的。
现在,这样做的原因是,当您访问时
Test.a,编译器将确保
Test已加载类并且所有
static字段均已初始化,因此它可以访问field
a。但是在访问
a简单名称时,编译器不确定的初始化程序
a是否已经运行,因为它可能仍在加载类中。
考虑以下加载类的过程:
- 加载类时,将为其中
static
声明的所有变量分配内存。至此,变量a
已经分配了内存(声明已完成) - 然后,所有
static
初始化程序都按照出现的顺序运行。- 第一个陈述是
Sysout(a);
。a
尚未初始化,因此您无法访问它。(错误) - 第二个陈述是
a = 99
。在这里,您实际上是在初始化变量a
。很好。 - 第三是
Sysout(Test.a)
-理由已经在上面发布。编译器知道Test
已经加载。 - 然后
static int a = 10
执行。它重新初始化a
为10
。记住,声明部分已经在第一步中得到了照顾。
- 第一个陈述是



