【问题标题】:Weird static initialization in Java when using Reflection使用反射时Java中奇怪的静态初始化
【发布时间】:2015-02-25 11:31:38
【问题描述】:

给定以下代码-sn-p,我得到输出“B”和“错误”:

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 而不进行反射,则不会发生问题。 为什么会这样,我该如何解决?

【问题讨论】:

  • 我会重构代码以消除两个类之间的循环依赖。这几乎肯定也能解决您的问题。

标签: java reflection static initialization


【解决方案1】:

问题与反射无关,与初始化类的顺序有关。

如果先初始化A类,它在B类中有依赖,B类尝试将B.c初始化为A的一个静态字段,但是这个字段仍然为null。

如果先初始化B类,它在A类中有依赖,A类被初始化,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

要解决该问题,您可以更改设计以删除循环依赖或确保以正确的顺序初始化类。

【讨论】:

  • 关闭。然而,问题不在于类的加载顺序。它们的顺序是初始化。或者更准确地说,是各个类的静态初始化发生的顺序。
  • @StephenC 感谢您的评论。那是我的观点。我改写了我的答案,以使术语更准确。
猜你喜欢
  • 2013-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多