使用反射时 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 以正确的顺序初始化。