为什么这个 toString() 方法会导致 StackOverFlowError?

Why is this toString() method causing StackOverFlowError?

我从this and this了解到 回答,您的代码可能进入无限循环导致 WhosebugError 的可能情况,但我不明白如何在此处复制相同的情况,

public class A {
  private B b = new B();
  @Override
  public String toString() {
      return "b "+b;
  }
}

public class B {
  private A a = new A();
  @Override
  public String toString() {
      return "";
  }
}

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

此代码生成的堆栈跟踪如下:-

Exception in thread "main" java.lang.WhosebugError
at Whosebugerror.B.<init>(B.java:5)
at Whosebugerror.A.<init>(A.java:5)
.
.
.

据我了解,当我在 main 方法中打印对象 'a' 时,它将调用 A class 的 toString 方法,在该方法中我返回 B class 这将隐式调用 B class 的 toString 方法。现在,在 B class 的 toString 方法中,我返回的只是一个空字符串。那么无限循环的范围如何以及在哪里出现在这里。请解释。

当你在 main 中调用 A a = new A(); 时,代码将调用 A 的构造函数,后者将调用 private B b = new B(); ,后者将调用 private A a = new A(); 等等无限循环: )

问题与 toString() 完全无关

它进入了事件的无限循环。在这种情况下,方法 toString() 是无辜的:

  1. 方法 main 创建 class A
  2. 的实例
  3. class A 在初始化时创建 class B 的实例
  4. class B 在初始化时创建 class A 的实例
  5. 转到步骤2

局部变量分配在堆栈上,WhosebugError 是错误递归调用的结果。

Thrown when a stack overflow occurs because an application recurses too deeply.

推荐的解决方案,删除class B中对class A的引用,因为它未被使用:

public class B {

    @Override
    public String toString() {
        return "";
    }
}

问题不在于 toString,而在于 private B b = new B();private A a = new A();

您正在创建 A,创建 B,创建 A,创建 B,依此类推

stacktrace 说的完全一样:B.<init> 表示初始值设定项,而不是 toString。它还指向抛出异常的行:B.java:5A.java:5

实时代码:https://ideone.com/H8wwOR

如果您确实需要在 B 中保留 A 并在 A 中保留 B 您可以使用构造函数参数或通过 setter 方法传递它们:

class A {
    private B b;

    public A(B b) {
        this.b = b;
    }
}

class B {
    private A a;

    public A getA() {
        return this.a;
    }

    public void setA(A a) {
        this.a = a;
    }
}

然后像这样使用它们:

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

这是一个简化的示例,您可以了解一下。在大型应用程序中,如果需要,您可能希望添加构建器、字段/构造函数参数注入或工厂。

每个 A 在其 b 字段中包含一个新的 B。每个 B 在其 a 字段中包含一个新的 A

创建一个新的 A 会自动创建一个新的 B,创建 that 会自动创建另一个新的 A,另一个新的 B,以此类推,直到堆栈溢出。

你的A包含B,A包含B,A包含B,A包含B,A包含B,A包含B,A包含B,A包含B,A包含B,A包含B ....

您在 B 中的 A 未被使用,因此您可以将其删除。

注意:堆栈跟踪显示问题出在构造中,即 () 与您的 toString() 无关;

在这种情况下,每当您创建 class A(或 B)的对象时,它也会在实例化时创建 class B(或 A,如果是 B)的新对象。现在这是一个永无止境的循环,因为无论何时创建 class A 或 B 的新对象,都会再次创建另一个 class 的新对象,从而导致对象创建的无限循环。因此,抛出 java.lang.WhosebugError 异常。