使用反射时 Java 中的奇怪静态初始化
Weird static initialization in Java when using Reflection
给出以下代码片段我得到输出 "B" 和 "error":
public class Test {
private static class A {
static final B c = new B();
}
private static class B extends A {
static final B c = A.c;
}
public static void main(String[] args) throws Exception {
for(Class<?> cls : Test.class.getDeclaredClasses()) {
if(cls.getDeclaredFields()[0].get(null) == null) {
System.out.println(cls.getSimpleName());
}
}
if(B.class.getDeclaredField("c").get(null) == null) {
System.out.println("error");
}
}
}
但它变得更加奇怪。如果我注释掉 for 循环,我不会得到任何输出 - 所以没有错误。此外,如果我在进行反射操作之前直接访问字段 B.c 而不进行反射,则不会出现问题。
为什么会这样,我该如何解决?
问题与反射无关,与 classes 的初始化顺序有关。
如果classA先初始化,它对classB有依赖,classB尝试初始化B.c到A的静态字段,但是该字段仍为空。
如果classB先初始化,它在classA中有依赖,classA被初始化,A.c设置为新的B实例并且 B.c 已正确初始化。
为了使示例更简单,此代码显示了简化的问题:
public static void main(String[] args) throws Exception {
System.out.println(A.c);
System.out.println(B.c);
}
输出:
Test$B@f72617
null
还有这个例子:
public static void main(String[] args) throws Exception {
System.out.println(B.c);
System.out.println(A.c);
}
输出:
Test$B@f72617
Test$B@f72617
要解决此问题,您可以更改设计以删除循环依赖或确保 classes 以正确的顺序初始化。
给出以下代码片段我得到输出 "B" 和 "error":
public class Test {
private static class A {
static final B c = new B();
}
private static class B extends A {
static final B c = A.c;
}
public static void main(String[] args) throws Exception {
for(Class<?> cls : Test.class.getDeclaredClasses()) {
if(cls.getDeclaredFields()[0].get(null) == null) {
System.out.println(cls.getSimpleName());
}
}
if(B.class.getDeclaredField("c").get(null) == null) {
System.out.println("error");
}
}
}
但它变得更加奇怪。如果我注释掉 for 循环,我不会得到任何输出 - 所以没有错误。此外,如果我在进行反射操作之前直接访问字段 B.c 而不进行反射,则不会出现问题。 为什么会这样,我该如何解决?
问题与反射无关,与 classes 的初始化顺序有关。
如果classA先初始化,它对classB有依赖,classB尝试初始化B.c到A的静态字段,但是该字段仍为空。
如果classB先初始化,它在classA中有依赖,classA被初始化,A.c设置为新的B实例并且 B.c 已正确初始化。
为了使示例更简单,此代码显示了简化的问题:
public static void main(String[] args) throws Exception {
System.out.println(A.c);
System.out.println(B.c);
}
输出:
Test$B@f72617
null
还有这个例子:
public static void main(String[] args) throws Exception {
System.out.println(B.c);
System.out.println(A.c);
}
输出:
Test$B@f72617
Test$B@f72617
要解决此问题,您可以更改设计以删除循环依赖或确保 classes 以正确的顺序初始化。