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

时间:2018-07-27 10:51:08

标签: java stack-overflow

我从thisthis了解到 答案是,您的代码可能陷入无限循环并导致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);
  }
}

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

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

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

6 个答案:

答案 0 :(得分:9)

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

您要创建的A会创建B,B会创建A会创建B,依此类推

stacktrace说的完全相同:B.<init>表示初始化程序,而不是toString。它还指出了抛出异常的行:B.java:5A.java:5

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

如果您确实需要将A中的BB中的A保留下来,则可以使用构造函数参数或使用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);

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

答案 1 :(得分:5)

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

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

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

  

由于应用程序的递归太深而导致堆栈溢出时抛出。

推荐的解决方案,请删除对类A中对类B的引用,因为它没有使用:

public class B {

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

答案 2 :(得分:2)

在您的主机中调用A a = new A();时,代码将调用A的构造函数,该构造函数将调用private B b = new B();,后者将调用private A a = new A();,依此类推,以进行无限循环:)< / p>

问题根本与toString()无关

答案 3 :(得分:0)

每个A的{​​{1}}字段中都包含一个新的B。每个b的{​​{1}}字段中都包含一个新的B

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

答案 4 :(得分:0)

您的A包含一个B,该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()无关;

答案 5 :(得分:0)

在这种情况下,无论何时创建类A(或B)的对象,只要实例化,它还将创建类B(或B的情况下为A)的新对象。现在,这是一个永无止境的循环,因为无论何时创建类A或B的新对象,再次创建另一个类的新对象也将导致对象创建的无限循环。因此,抛出java.lang.StackOverflowError异常。