java类中的循环依赖

我有以下课程。

public class B { public A a; public B() { a= new A(); System.out.println("Creating B"); } } 

 public class A { public B b; public A() { b = new B(); System.out.println("Creating A"); } public static void main(String[] args) { A a = new A(); } } 

可以清楚地看到,类之间存在循环依赖关系。 如果我尝试运行A类,我最终得到一个StackOverflowError

如果创建了依赖关系图,其中节点是类,则可以轻松识别此依赖关系(至少对于具有少量节点的图)。 那为什么JVM不能识别这个,至少在运行时? JVM可以在开始执行之前至少发出警告,而不是抛出StackOverflowError

[更新]某些语言不能具有循环依赖关系,因为这样就不会构建源代码。 例如, 请参阅此问题和接受的答案。 如果循环依赖是C#的设计气味那么为什么它不适用于Java呢? 只是因为Java可以(编译循环依赖的代码)?

[update2]最近发现了jCarder 。 根据该网站,它通过动态检测Java字节代码并在对象图中查找周期来发现潜在的死锁。 任何人都可以解释该工具如何找到周期?

类A的构造函数调用类B的构造函数。类B的构造函数调用类A的构造函数。您有一个无限的递归调用,这就是为什么你最终得到一个StackOverflowError

Java支持在类之间具有循环依赖关系,此处的问题仅与构造函数相互调用有关。

您可以尝试使用以下内容:

 A a = new A(); B b = new B(); a.setB(b); b.setA(a); 

它在Java中完全有效,在2个类之间有一个循环关系(虽然可以询问有关设计的问题),但是在你的情况下你有不同的动作,每个实例在它的构造函数中创建另一个的实例(这是实际的StackOverflowError的原因)。

这种特殊模式是已知的相互递归,其中有2个方法A和B(构造函数大多只是方法的一个特例)和A调用B和B调用A.检测这两个方法之间关系的无限循环是可能在琐碎的情况下(你提供的那个),但解决一般情况类似于解决停止问题。 鉴于解决暂停问题是不可能的,因此即使对于简单的情况,编制者通常也不会费心。

有可能使用FindBugs模式覆盖一些简单的情况,但对于所有情况都不正确。

它不一定像你的例子那么容易。 我相信解决这个问题就等于解决暂停问题 – 正如我们所知 – 这是不可能的。

如果你真的有这样的用例,你可以按需创建对象(懒惰)并使用getter:

 public class B { private A a; public B() { System.out.println("Creating B"); } public A getA() { if (a == null) a = new A(); return a; } } 

(类似于A类)。 因此,只有当您执行以下操作时,才会创建必要的对象:

 a.getB().getA().getB().getA() 

对依赖项使用组合和构造函数注入的getter / setter的类似解决方法。 需要注意的重要一点是,对象不会为其他类创建实例,而是传入它们(也就是注入)。

 public interface A {} public interface B {} public class AProxy implements A { private A delegate; public void setDelegate(A a) { delegate = a; } // Any implementation methods delegate to 'delegate' // public void doStuff() { delegate.doStuff() } } public class AImpl implements A { private final B b; AImpl(B b) { this.b = b; } } public class BImpl implements B { private final A a; BImpl(A a) { this.a = a; } } public static void main(String[] args) { A proxy = new AProxy(); B b = new BImpl(proxy); A a = new AImpl(b); proxy.setDelegate(a); } 

请查看我在http://java.dzone.com/articles/tackling-circular-dependency上的文章

我想它会清除你的怀疑……