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

Rah*_*pta 8 java stack-overflow

我已经从这个这个 答案中理解了你的代码可能进入无限循环导致stackOverFlowError的可能情况,但我不明白如何在这里复制相同的场景,

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 StackoverflowErrorTest {
  public static void main(String[] args) {
     A a = new A();
     System.out.println(a);
  }
}
Run Code Online (Sandbox Code Playgroud)

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

Exception in thread "main" java.lang.StackOverflowError
at stackoverflowerror.B.<init>(B.java:5)
at stackoverflowerror.A.<init>(A.java:5)
.
.
.
Run Code Online (Sandbox Code Playgroud)

根据我的理解,当我在main方法中打印对象'a'时,它将调用A类的toString方法,在该方法中,我将返回B类的对象,该对象将隐式调用B类的toString方法.现在,在B类的toString方法中,我返回的是一个空字符串.那么无限循环的范围如何以及在何处进入图片.请解释.

awe*_*oon 9

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

您正在创建一个创建B的A,它创建一个创建B的A,依此类推

而stacktrace说的完全相同:B.<init>意味着初始化器,而不是toString.它还指向抛出异常的行:B.java:5A.java:5

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

如果你真的需要保持ABBA,你可以使用任何参数的构造函数或通过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;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后使用它们像:

B b = new B();
A a = new A(b);
b.setA(a);
Run Code Online (Sandbox Code Playgroud)

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


Nik*_*las 5

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

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

局部变量在堆栈上分配,这StackOverflowError是一个错误的递归调用的结果.

在发生堆栈溢出时抛出,因为应用程序过于严重.

建议的解决方案,删除类A中类的引用,B因为它未使用:

public class B {

    @Override
    public String toString() {
        return "";
    }
}
Run Code Online (Sandbox Code Playgroud)