我在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;
}
}
答案 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;
}
}
,类似于Bar
和Baz
类。
加载第一个类时,会调用其中一个create
方法。这将设置temp变量并调用第二个create
方法,该方法将设置另一个临时变量并调用第三个create
方法,该方法将设置另一个临时变量并递归调用第一个方法。但由于该类中的临时变量已经设置,因此该方法只返回它,并且不再有递归。
有些注意事项:我需要添加一个不是tempUnknownFoo
的新final
;否则无法在createUnknownFoo
方法中设置。 createUnknownFoo
方法是包私有的。我假设所有三个类都在同一个包中,因此他们都应该能够调用其他类#' createUnknown
方法,但不在该软件包中的其他类无法实现。我添加了一个仅由createUnknown
使用的私有无参数构造函数。我必须从final
移除bar
,但由于它private
它不应该成为问题。
P.S。请不要过于严格地对循环依赖关系进行评论。 经常,循环依赖是设计缺陷的标志;应用程序中类的结构通常最终会产生某种层次结构或者#34;层"它们的结构,在这种情况下,循环依赖通常意味着某人以一种黑客的方式添加了一个新功能,而没有考虑它如何适应整体结构。但是,例如,在编译器中,您将会在各处实现相互引用的各种实体,并且会存在循环依赖关系。循环依赖项还有其他合法用法。肯定存在大量非法用途,但我认为没有人认识到有正当理由使用它们是正确的。你的很可能是合法用途,但我不能说。太多"经验法则"太多时间都变成了教条。