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

Java 为什么这个toString()方法会导致StackOverflowerError?,java,stack-overflow,Java,Stack Overflow,我已经从和了解了 回答,可能的情况是,您的代码可能会进入无限循环,导致StackOverflowerError,但我不明白相同的情况是如何在这里复制的 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

我已经从和了解了 回答,可能的情况是,您的代码可能会进入无限循环,导致StackOverflowerError,但我不明白相同的情况是如何在这里复制的

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”java.lang.StackOverflower中出现异常 在StackOverflowerr.B.(B.java:5) 在StackOverflowerr.A.(A.java:5) . . .
根据我的理解,当我在main方法中打印对象“a”时,它将调用一个类的toString方法,在该方法中,我将返回B类的对象,该对象将隐式调用B类的toString方法。现在,在B类的toString方法中,我返回的只是一个空字符串。那么无限循环的范围是如何以及在哪里出现的呢。请解释。

当您在主菜单中调用
A A=newa(),代码将调用A的构造函数,该构造函数将调用
private B=new B()
,它将调用
私有A=newa()等:)


这个问题根本与
toString()
无关

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

  • 方法
    main
    创建类
    A
  • A
    在初始化时创建类
    B
    的实例
  • B
    在初始化时创建类
    A
    的实例
  • 转到步骤
    2
  • 局部变量在堆栈上分配,并且是错误递归调用的结果

    由于应用程序递归太深而发生堆栈溢出时引发

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

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

    问题不在于
    toString
    ,而在于
    private B=new B()
    私有A=新A()

    你正在创造一个创造B的A,创造一个创造B的A,依此类推

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

    实时代码:

    如果您确实需要在
    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
    ,创建一个新的
    a
    ,以及另一个新的
    B
    ,依此类推,直到堆栈溢出。

    您的A包含一个B,其中包含一个A,其中包含一个B,其中包含一个A,其中包含一个B,其中包含一个A,其中包含一个B,其中包含一个A,其中包含一个B

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


    注意:堆栈跟踪显示问题在构造ie()中,与toString()无关

    在此场景中,无论何时创建类A(或B)的对象,只要实例化,它也会创建类B(或B)的新对象。现在,这是一个永无止境的循环,因为无论何时,只要为类a或类B创建一个新对象,另一个类的新对象也会被创建,从而导致对象创建的无限循环。因此,抛出java.lang.StackOverflowerError异常。

    请随意评论这两个
    toString()
    方法,看看它们是否与问题有关。我找不到重复的堆栈溢出。但这里有一个骗局: