为什么我会在这里收到StackOverflowError错误?

3
为什么这段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();
    }
}

你看了错误的堆栈跟踪吗?那应该能给你一些关于发生了什么的线索。这与类型参数无关 - 如果你删除它们,它仍然会产生 StackOverflowError - Jesper
3
在stackoverflow上提出了一个好问题。(: - Ghyath Serhal
@Jesper:SomeClassKiller被初始化了无数次。但我不明白为什么。 - Roman
6个回答

13

泛型部分并不重要,嵌套类也并不重要。看看这对几乎等价的类,应该更加明显:

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

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

因此,子类构造函数调用超类构造函数 - 然后创建一个新的子类,该子类调用超类构造函数,从而创建一个新的子类,依此类推... 崩溃!


呵呵..我绝对确定泛型的问题,却没有注意到这个东西 :) - Roman
super(); 几乎等同于 this = new SuperClass();。现在应该很明显了... - Vincent Robert

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
    }
}

1

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


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。

0

main()方法正在创建SomeClass的新实例,该实例调用SomeClass构造函数,该构造函数创建SomeClassKiller的新实例,默认情况下调用父构造函数并导致stackoverflow错误。

为避免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();
    }
}

0

构造函数是自上而下调用的,也就是说如果一个类 A 继承自 B,那么 A 的构造函数将首先调用父类构造函数 (B)。

在你的情况下,new SomeClassKiller() 递归调用了 SomeClass 的构造函数,然后又构造了另一个 SomeClassKiller … 就是这样。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接