静态变量初始化的顺序,Java
可能重复:
Java静态类初始化
以什么顺序执行的类中的静态块和静态变量?
当我运行这段代码时答案是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:对于一些我不知道的原因,当^而不是“k”它的“Test.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。
很长的解释
让我们使用这个例子 ,因为你的例子有点简单:
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节 :
程序中的每个变量在使用其值之前必须具有值:
- 每个类变量,实例变量或数组组件在创建时都使用默认值进行初始化
(规范中的以下行指定了所有类型的默认值,基本上是某种forms的0,例如0.0d
, null
, false
等)
因此,在初始化类之前(由于其中一个原因 ),变量将保持初始值。
根据详细的初始化程序 (这里仅引用有趣的步骤,并强调我的):
6. […]然后,初始化
final
类变量和接口的字段,其值是编译 时常量表达式 (§8.3.2.1,§9.3.1,§13.4.9,§15.28)。[…]
9.接下来,按文本顺序执行类的类变量初始值设定项和静态初始值设定项,或接口的字段初始值设定项,就好像它们是单个块一样。
让我们看看步骤6, final
有4个类变量: stat1
, str2
, second
, lazy
。
由于10
是常量表达式,因此是"sdfff"
,并且由于执行的顺序,不可能观察到str2
和stat1
的初始值。 为了进行观察,你最早能做的就是在第9步。
second
情况表明,当右侧不是编译时常量表达式时,其初始值是可见的。
lazy
的情况是不同的,因为赋值是在静态块中完成的,因此在步骤9中发生 – 因此可以观察其初始值。 (好吧,编译器会仔细检查lazy
是否只分配了一次)。
在使用编译时常量表达式初始化最终类变量之后,执行静态块和其余的初始化程序。
从示例中可以看出,静态块和初始化根据文本顺序发生 – 使用str
变量演示 – 它首先打印为null
,然后something
,然后是crap
。