静态变量初始化顺序,Java
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/13554507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Order of static variable initialization, Java
提问by Andrzej Rehmann
Possible Duplicate:
Java static class initialization
in what order are static blocks and static variables in a class executed?
When I run this code the answer is 1, I thought it would be 2. What is the order of initialization and the value of k in each step?
当我运行这段代码时,答案是 1,我以为应该是 2。每个步骤中初始化的顺序和 k 的值是什么?
public class Test {
static {k = 2;}
static int k = 1;
public static void main(String[] args) {
System.out.println(k);
}
}
Edit 1: As a follow up to "k is set to default value" then why this next code doesn't compile? Theres an error "Cannot reference a field before it's defined".
编辑 1:作为“k 设置为默认值”的后续,那么为什么下一个代码不能编译?出现错误“在定义字段之前无法引用字段”。
public class Test {
static {System.out.println(k);}
static int k=1;
public static void main(String[] args) {
System.out.println(k);
}
}
Edit 2: For some unknow to me reason it^ works when instead of "k" its "Test.k".
编辑 2:对于我不知道的原因,它 ^ 在而不是“k”它的“Test.k”时起作用。
Thanks for all the answers. this will sufice :D
感谢所有的答案。这就足够了:D
采纳答案by tibtof
They are executed in the order that you write them. If the code is:
它们按照您编写它们的顺序执行。如果代码是:
public class Test {
static int k = 1;
static {k = 2;}
public static void main(String[] args) {
System.out.println(k);
}
}
then the output becomes 2.
那么输出变为2。
The order of initialization is: ..the class variable initializers and static initializers of the class..., in textual order, as though they were a single block.
初始化的顺序是:..类变量初始化器和类的静态初始化器...,按文本顺序,就好像它们是一个单一的块。
And the values (for your code) are: k = 0 (default), then it's set to 2, then it's set back to 1.
并且值(对于您的代码)是:k = 0(默认值),然后将其设置为 2,然后将其设置回 1。
You can check that it's actually set to 2 by running the following code:
您可以通过运行以下代码来检查它是否实际设置为 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);
}
}
回答by nhahtdh
Short answer
简答
When the initialization of the class starts, k
will have initial value of 0.
当类的初始化开始时,k
初始值为 0。
The static block (since it precedes the assignment in the declaration) is then executed, and k
will be assigned 2.
然后执行静态块(因为它在声明中的赋值之前),k
并将被赋值为 2。
Then the initializer in the declaration is executed, and k
will be assigned 1.
然后执行声明中的初始化程序,k
并将被赋值为 1。
Long explanation
长解释
Let us use this example, since your example is a bit simple:
让我们使用这个例子,因为你的例子有点简单:
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);
}
}
According to Java Language Specification, from section 4.12.5:
根据Java Language Specification,来自第 4.12.5 节:
Every variable in a program must have a value before its value is used:
- Each class variable, instance variable, or array component is initialized with a default value when it is created
程序中的每个变量在使用其值之前都必须有一个值:
- 每个类变量、实例变量或数组组件在创建时都使用默认值进行初始化
(The following lines from the specification specify the default value for all the types, basically some form of 0, such as 0
, 0.0d
, null
, false
, etc.)
(从本说明书中的以下各行指定的默认值的所有类型,基本上某种形式的0,如0
,0.0d
,null
,false
,等等)
So before the class is initialized (due to one of these reasons), the variables will hold an initial value.
所以在类被初始化之前(由于这些原因之一),变量将保持一个初始值。
According to the detailed initialization procedure(only the interesting steps are quoted here, and emphasis mine):
根据详细的初始化过程(这里只引用有趣的步骤,重点是我的):
6. [...] Then, initialize the
final
class variablesand fields of interfaceswhose values are compile-timeconstant expressions(§8.3.2.1, §9.3.1, §13.4.9, §15.28).[...]
9. Next, execute either the class variable initializers and static initializers of the class, or the field initializers of the interface, in textual order, as though they were a single block.
6. [...] 然后,初始化其值为编译时常量表达式的
final
类变量和接口字段(第 8.3.2.1 节、第 9.3.1 节、第 13.4.9 节、第 15.28 节)。[...]
9. 接下来,按文本顺序执行类的类变量初始化器和静态初始化器,或接口的字段初始化器,就好像它们是单个块一样。
Let us look at step 6, with the 4 final
class variables: stat1
, str2
, second
, lazy
.
让我们看看第 6 步,有 4 个final
类变量:stat1
, str2
, second
, lazy
。
Since 10
is constant expression, and so is "sdfff"
, and due to the order of execution, it is not possible to observethe initial value for str2
and stat1
. In order to make an observation, the earliest you can do is in step 9.
由于10
是常量表达式,所以是"sdfff"
,并且由于执行的顺序,就不可能观察初始值str2
和stat1
。为了进行观察,您最早可以在步骤 9 中进行。
The case of second
demonstrate that when the right hand side is not a compile-time constant expression, so its initial value is visible.
例子second
说明当右边不是一个编译时常量表达式,所以它的初始值是可见的。
The case of lazy
is different, since the assignment is done in static block, and hence happen in step 9 - so it is possible to observe its initial value. (Well, the compiler checks carefully that lazy
is assigned exactly once).
的情况lazy
不同,因为赋值是在静态块中完成的,因此发生在第 9 步 - 所以可以观察到它的初始值。(好吧,编译器仔细检查lazy
只分配了一次)。
After the initialization of final class variables with compile-time constant expression comes the execution of static blocks and the rest of the initializers.
在使用编译时常量表达式初始化 final 类变量之后,接下来是执行静态块和其余的初始化程序。
As you can see from the example, the static blocks and initialization happens according to textual order - demonstrated with the use of str
variable - it is first printed out as null
, then something
, then crap
.
从示例中可以看出,静态块和初始化根据文本顺序发生 - 使用str
变量进行演示- 它首先打印为null
,然后something
,然后crap
。