为什么我在这里得到StackOverflowError?

时间:2010-12-17 11:02:11

标签: java generics recursion stack-overflow

为什么这个java代码会产生StackOverflowError?我知道这与递归泛型类型参数有某种联系。但我不明白整个机制。

public class SomeClass<T extends SomeClass> {

    SomeClass() {
        new SomeClassKiller();
    }

    private class SomeClassKiller extends SomeClass<T> {
    }

    public static void main(String[] args) {
        new SomeClass();
    }
}

6 个答案:

答案 0 :(得分:13)

通用部分并不重要 - 类嵌套也不重要。看看这个大多数等同的类,它应该更明显:

public class SuperClass
{
    public SuperClass()
    {
        new SubClass();
    }
}

public class SubClass extends SuperClass
{
    public SubClass()
    {
        super();
    }
}

所以子类构造函数调用超类构造函数 - 然后创建一个新的子类,调用超类构造函数,创建一个新的子类,等等... bang!

答案 1 :(得分:2)

这里是从另一个构造函数中调用一个构造函数,并从前一个构造函数链调用,参见下面的注释

public class SomeClass<T extends SomeClass> {

    SomeClass() {//A
        new SomeClassKiller();// calls B
    }

    private class SomeClassKiller extends SomeClass<T> {//B
               //calls A
    }

    public static void main(String[] args) {
        new SomeClass(); //calls A
    }
}

答案 2 :(得分:1)

这是因为SomeClass和类之间发生递归构造函数调用 SomeClassKiller。

答案 3 :(得分:0)

public class SomeClass<T extends SomeClass> {

    SomeClass() {
        new SomeClassKiller();
    }

    private class SomeClassKiller extends SomeClass<T> {
       public SomeClassKiller()
       {
         super(); //calls the constructor of SomeClass
        }
    }

    public static void main(String[] args) {
        new SomeClass();
    }
}

编译器生成的代码是这样的,所以当你创建一个对象时,它会递归地调用SomeClass和SomeClassKiller。

答案 4 :(得分:0)

从上到下调用​​构造函数,即如果类A派生自B,则A的构造函数将首先调用父构造函数(B)。

在你的情况下,new SomeClassKiller()以递归方式调用SomeClass的构造函数,而构造函数又构造了另一个SomeClassKiller ......就在那里。

答案 5 :(得分:0)

main()方法正在创建SomeClass的新实例,该实例调用SomeClass 构造函数,创建SomeClassKiller的新实例default调用父构造函数并发生stackoverflow。

避免堆栈溢出。将代码更改为如下所示:

public class SomeClass<T extends SomeClass> {

    SomeClass() {
        new SomeClassKiller();
    }

    private class SomeClassKiller extends SomeClass<T> {
        public SomeClassKiller(){
            //super(); does this by default, but is now commented out and won't be called.
        }

    }

    public static void main(String[] args) {
        new SomeClass();
    }
}