在静态初始化程序中引用Self

时间:2014-07-27 01:44:39

标签: java class exception static null

我在java程序中遇到三个类的问题,我在静态初始化程序中使用相同类类型的public static final引用,但这些类也有public static final个自己的引用,并且最终指向未初始化的类(导致null)。我正在使用一种使用静态引用作为常量的策略,但这种奇怪的链接行为一直在发生,如果无法解决这个问题会有什么替代方案,并且可以解决问题吗?

代码:

public class Foo{
    public static final Foo UNKNOWN_FOO = new Foo(Bar.UNKNOWN_BAR);
    private final Bar bar;
    public Foo(Bar bar){
        this.bar = bar;
    }
}

public class Bar{
    public static final Bar UNKNOWN_BAR = new Bar(Baz.UNKNOWN_BAZ);
    private final Baz baz;
    public Bar(Baz baz){
        this.baz = baz;
    }
}

public class Baz{
    public static final Baz UNKNOWN_BAZ = new Baz(Foo.UNKNOWN_FOO);
    private final Foo foo;
    public Baz(Foo foo){
        this.foo = foo;
    }
}

3 个答案:

答案 0 :(得分:1)

正如Eran所提到的,尽量避免循环依赖。来自google guice的最佳实践的以下网页描述了如何避免循环依赖并解决它们: https://github.com/google/guice/wiki/CyclicDependencies

答案 1 :(得分:1)

我很确定无法构建具有final字段的实例网络...而不使用一些讨厌的反射来修改final值。

考虑一下:

public class Foo{
    public static final Foo UNKNOWN_FOO = new Foo(Foo.UNKNOWN_FOO);
    private final Foo foo;
    public Foo(Foo foo){
        this.foo = foo;
    }
}

即使这样也行不通。 foo的{​​{1}}字段为Foo.UNKNOWN_FOO

要使这项工作,null字段或foo字段必须是非最终字段。例如:

UNKNOWN_FOO

在这种情况下,我们可能会因为public class Foo{ public static final Foo UNKNOWN_FOO; static { Foo tmp = new Foo(null); tmp.foo = tmp; UNKNOWN_FOO = tmp; } private Foo foo; // NOT final!! public Foo(Foo foo){ this.foo = foo; } } foo并且没有设置者而放弃private

在更复杂的情况下,您将需要公开一个setter方法,以便在创建所有静态最终对象后,某些东西可以“关闭循环”。但你可以安排setter只能调用一次; e.g。

   public void setFoo(Foo foo) {
       if (this.foo != null) {
           throw new IllegalStateException("Already set");
       }
       this.foo = foo;
   }

但我同意其他评论和答案。这些循环依赖对我来说有“糟糕的设计”气味......

答案 2 :(得分:1)

我认为这会有效,但我还没有对它进行过测试(编辑:我已对其进行了测试,并且有效):

public class Foo{
    private static Foo tempUnknownFoo = null;
    public static final Foo UNKNOWN_FOO = createUnknownFoo();
    static Foo createUnknownFoo() {
        if (tempUnknownFoo == null) {
            tempUnknownFoo = new Foo();
            tempUnknownFoo.bar = Bar.createUnknownBar();
        }
        return tempUnknownFoo;
    }        
    private Foo() { }

    private Bar bar;
    public Foo(Bar bar){
        this.bar = bar;
    }
}

,类似于BarBaz类。

加载第一个类时,会调用其中一个create方法。这将设置temp变量并调用第二个create方法,该方法将设置另一个临时变量并调用第三个create方法,该方法将设置另一个临时变量并递归调用第一个方法。但由于该类中的临时变量已经设置,因此该方法只返回它,并且不再有递归。

有些注意事项:我需要添加一个不是tempUnknownFoo的新final;否则无法在createUnknownFoo方法中设置。 createUnknownFoo方法是包私有的。我假设所有三个类都在同一个包中,因此他们都应该能够调用其他类#' createUnknown方法,但不在该软件包中的其他类无法实现。我添加了一个仅由createUnknown使用的私有无参数构造函数。我必须从final移除bar,但由于它private它不应该成为问题。

P.S。请不要过于严格地对循环依赖关系进行评论。 经常,循环依赖是设计缺陷的标志;应用程序中类的结构通常最终会产生某种层次结构或者#34;层"它们的结构,在这种情况下,循环依赖通常意味着某人以一种黑客的方式添加了一个新功能,而没有考虑它如何适应整体结构。但是,例如,在编译器中,您将会在各处实现相互引用的各种实体,并且会存在循环依赖关系。循环依赖项还有其他合法用法。肯定存在大量非法用途,但我认为没有人认识到有正当理由使用它们是正确的。你的很可能是合法用途,但我不能说。太多"经验法则"太多时间都变成了教条。