解释 java 编译顺序
explain java compile order
v2
第一次进入A的c'tor时是null,但是如果我把v2
的声明&初始化放在instance
之前它就会有值;这是为什么?
public class A {
private static final String v1 = new String(new byte[]{'a', 'b'});
private static A instance = new A();
private static final String v2 = new String(new byte[]{'b', 'c'});
private A() {
System.out.printf("A c'tor\tv1 [%s]\tv2 [%s]\n", v1, v2);
}
public static void main(String[] args) {
System.out.println("start main");
new A();
System.out.println("end main");
}
}
输出:
A c'tor v1 [ab] v2 [null]
start main
A c'tor v1 [ab] v2 [bc]
end main
此外,如果我将 v2
的初始化更改为:
private static final String v2 = "ab";
它确实初始化了 v2
,输出是:
A c'tor v1 [ab] v2 [ab]
start main
A c'tor v1 [ab] v2 [ab]
end main
编辑
第二部分的另一个测试:
public class A {
private static final String v1 = new String(new byte[]{'a', 'b'});
private static transient A instance = new A();
private static final String v2 = new String(new byte[]{'b', 'c'});
private static final String v3 = new String("ab");
private static final String v4 = "ab";
private A() {
System.out.printf("A c'tor\tv1 [%s] v2 [%s] v3 [%s] v4 [%s]\n", v1, v2, v3, v4);
}
public static void main(String[] args) {
System.out.println("start main");
new A();
System.out.println("end main");
}
}
输出:
A c'tor v1 [ab] v2 [null] v3 [null] v4 [ab]
start main
A c'tor v1 [ab] v2 [bc] v3 [ab] v4 [ab]
end main
当 class A 初始化时(在执行 main
之前),静态变量按照它们在源文件中出现的顺序进行初始化。
- 第一个 v1
- then instance(打印
A c'tor v1 [ab] v2 [null]
因为它的初始化涉及创建 A 的实例)- 它在 v2
之前初始化,这就是为什么 v2
仍然是 null
.
- 然后是 v2
初始化后,main
方法被执行,并产生接下来的 3 行输出。在 main
方法中创建 A
的新实例会产生与先前构造函数调用不同的输出,因为此时 v1
和 v2
都已初始化。
编辑:
关于您更新的问题:
如果您关注 initialization procedure in JLS 12.4.2:
- Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize the final class variables and fields of interfaces whose values are compile-time constant expressions.
...
- 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.
如您所见,值为 compile-time constant expressions 的最终静态变量在其余静态变量之前被初始化。因此,将 v2
的值更改为常量 "ab"
会导致 v2
在 instance
变量之前初始化,这解释了不同的输出。
v2
第一次进入A的c'tor时是null,但是如果我把v2
的声明&初始化放在instance
之前它就会有值;这是为什么?
public class A {
private static final String v1 = new String(new byte[]{'a', 'b'});
private static A instance = new A();
private static final String v2 = new String(new byte[]{'b', 'c'});
private A() {
System.out.printf("A c'tor\tv1 [%s]\tv2 [%s]\n", v1, v2);
}
public static void main(String[] args) {
System.out.println("start main");
new A();
System.out.println("end main");
}
}
输出:
A c'tor v1 [ab] v2 [null]
start main
A c'tor v1 [ab] v2 [bc]
end main
此外,如果我将 v2
的初始化更改为:
private static final String v2 = "ab";
它确实初始化了 v2
,输出是:
A c'tor v1 [ab] v2 [ab]
start main
A c'tor v1 [ab] v2 [ab]
end main
编辑
第二部分的另一个测试:
public class A {
private static final String v1 = new String(new byte[]{'a', 'b'});
private static transient A instance = new A();
private static final String v2 = new String(new byte[]{'b', 'c'});
private static final String v3 = new String("ab");
private static final String v4 = "ab";
private A() {
System.out.printf("A c'tor\tv1 [%s] v2 [%s] v3 [%s] v4 [%s]\n", v1, v2, v3, v4);
}
public static void main(String[] args) {
System.out.println("start main");
new A();
System.out.println("end main");
}
}
输出:
A c'tor v1 [ab] v2 [null] v3 [null] v4 [ab]
start main
A c'tor v1 [ab] v2 [bc] v3 [ab] v4 [ab]
end main
当 class A 初始化时(在执行 main
之前),静态变量按照它们在源文件中出现的顺序进行初始化。
- 第一个 v1
- then instance(打印
A c'tor v1 [ab] v2 [null]
因为它的初始化涉及创建 A 的实例)- 它在v2
之前初始化,这就是为什么v2
仍然是null
. - 然后是 v2
初始化后,main
方法被执行,并产生接下来的 3 行输出。在 main
方法中创建 A
的新实例会产生与先前构造函数调用不同的输出,因为此时 v1
和 v2
都已初始化。
编辑:
关于您更新的问题:
如果您关注 initialization procedure in JLS 12.4.2:
- Otherwise, record the fact that initialization of the Class object for C is in progress by the current thread, and release LC. Then, initialize the final class variables and fields of interfaces whose values are compile-time constant expressions.
...
- 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.
如您所见,值为 compile-time constant expressions 的最终静态变量在其余静态变量之前被初始化。因此,将 v2
的值更改为常量 "ab"
会导致 v2
在 instance
变量之前初始化,这解释了不同的输出。