可能重复:Java static class initializationin what order are static blocks and static variables in a class executed?
当我运行此代码时,答案为1,我认为应该是2。初始化的顺序和每个步骤中k的值是什么?
public class Test {
static {k = 2;}
static int k = 1;
public static void main(String[] args) {
System.out.println(k);
}
}
编辑1:跟进“ k设置为默认值”,那么为什么下一个代码不能编译?错误“在定义字段之前无法引用它”。
public class Test {
static {System.out.println(k);}
static int k=1;
public static void main(String[] args) {
System.out.println(k);
}
}
编辑2:由于某些我不知道的原因,它^在代替它的“ Test.k”而不是“ k”时起作用。
感谢所有答案。这将满足:D
它们按照您编写它们的顺序执行。如果代码是:
public class Test {
static int k = 1;
static {k = 2;}
public static void main(String[] args) {
System.out.println(k);
}
}
然后输出变为2。
并且(对于您的代码而言)值为:k = 0(默认值),然后将其设置为2,然后将其设置回1。
您可以通过运行以下代码来检查它实际上是否设置为2:
private static class Test {
static {
System.out.println(Test.k);
k = 2;
System.out.println(Test.k);
}
static int k = 1;
public static void main(String[] args) {
System.out.println(k);
}
}
简短回答
当类的初始化开始时,k
的初始值为0。
然后执行静态块(因为它在声明中的赋值之前),并且将k
赋值为2。
然后执行声明中的初始化程序,并将k
分配为1。
详细说明
让我们使用this example,因为您的示例有点简单:
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 Language Specification,来自section 4.12.5:
程序中的每个变量都必须有一个值,然后才能使用它的值:
- 每个类变量,实例变量或数组组件在创建时均使用默认值初始化
(规范的以下几行指定所有类型的默认值,基本上是0的某种形式,例如0
,0.0d
,null
,false
等)
因此,在初始化类之前(由于[C0]之一,变量将保留一个初始值。
根据these reasons(仅在此处引用有趣的步骤,并强调我的意思:):
6。[...]然后,初始化其值为compile-time constant expressions(第8.3节)的detailed initialization procedure类变量和接口的字段。 2.1,§9.3.1,§13.4.9,§15.28)。
[...]
9。接下来,以文本顺序执行类的类变量初始化器和静态初始化器,或接口的字段初始化器,就好像它们是单个块一样。
[让我们看一下第6步,有4个final
类变量:final
,stat1
,str2
,second
。
因为lazy
是常数表达式,10
也是如此,并且由于执行顺序,所以不可能观察 "sdfff"
和str2
的初始值。为了进行观察,您最早可以做的是在步骤9中。
stat1
的情况表明,当右侧不是编译时常量表达式时,则其初始值可见。
second
的情况不同,因为分配是在静态块中完成的,因此发生在步骤9中-因此可以观察其初始值。 (好吧,编译器会仔细检查lazy
是否恰好分配了一次)。
使用编译时常量表达式初始化最终类变量后,将执行静态块和其余初始化程序。
如您从示例中看到的,静态块和初始化根据文本顺序进行-通过使用lazy
变量进行演示-首先将其打印为str
,然后是null
,然后是something
。