简短的回答
当类的初始化开始时,初始值为 0。k
然后执行静态块(因为它在声明中的赋值之前),并将被赋值 2。k
然后执行声明中的初始值设定项,并将分配 1。k
长篇解释
让我们使用这个例子,因为你的例子有点简单:
class TestInitOrder {
static {
System.out.println(TestInitOrder.stat1);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
str = "something";
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
private static final int stat1 = 10;
static final String str2 = "sdfff";
static String str = "crap";
private static int stat2 = 19;
static final Second second = new Second();
static final int lazy;
static {
lazy = 20;
}
static {
System.out.println(TestInitOrder.str2);
System.out.println(TestInitOrder.stat2);
System.out.println(TestInitOrder.str);
System.out.println(TestInitOrder.lazy);
System.out.println(TestInitOrder.second);
}
public static void main(String args[]) {
}
}
class Second {
public Second() {
System.out.println(TestInitOrder.second);
}
}
根据 Java 语言规范,从 4.12.5 节中:
程序中的每个变量在使用其值之前都必须有一个值:
- 每个类变量、实例变量或数组组件在创建时都使用默认值进行初始化
(规范中的以下行指定了所有类型的默认值,基本上是某种形式的 0,例如 、 、 、 等。0
0.0d
null
false
因此,在初始化类之前(由于这些原因之一),变量将保存初始值。
根据详细的初始化过程(这里只引用了有趣的步骤,并强调我的):
6. [...]然后,初始化其值为编译时常量表达式的接口的最终
类变量和字段 (§8.3.2.1, §9.3.1, §13.4.9, §15.28)。
[...]
9. 接下来,按文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。
让我们看一下步骤 6,其中包含 4 个类变量:、 、 、 。final
stat1
str2
second
lazy
由于 是常量表达式,因此是 ,并且由于执行顺序,因此无法观察到 和 的初始值。为了进行观察,您可以做的最早是在步骤9中。10
"sdfff"
str2
stat1
演示的情况是,当右侧不是编译时常量表达式时,因此其初始值是可见的。second
的情况是不同的,因为赋值是在静态块中完成的,因此发生在步骤9中 - 因此可以观察其初始值。(好吧,编译器会仔细检查只分配一次)。lazy
lazy
在使用编译时常量表达式初始化最终类变量之后,将执行静态块和初始值设定项的其余部分。
从示例中可以看出,静态块和初始化根据文本顺序进行 - 通过使用变量进行演示 - 它首先打印出来为,然后,然后。str
null
something
crap