Почему я получаю StackOverflowError здесь? - PullRequest
3 голосов
/ 17 декабря 2010

Почему этот код 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 ]

13 голосов
/ 17 декабря 2010

Общая часть не имеет значения - и при этом не имеет значения, что класс является вложенным. Посмотрите на эту в основном эквивалентную пару классов, и она должна быть более очевидной:

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

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

Таким образом, конструктор подкласса вызывает конструктор суперкласса, который затем создает новый подкласс, который вызывает конструктор суперкласса, который создает новый подкласс, и т.д ... bang!

2 голосов
/ 17 декабря 2010

Здесь он вызывает один конструктор из другого, а из него предыдущий, циклическая цепочка конструкторов, см. Комментарии ниже

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 голос
/ 17 декабря 2010

Это происходит из-за рекурсивных вызовов конструктора , происходящих между классами SomeClass и SomeClassKiller.

0 голосов
/ 17 декабря 2010

Метод main() создает новый экземпляр SomeClass, который вызывает конструктор SomeClass , который создает новый экземпляр SomeClassKiller, который по умолчанию вызывает родительский конструктор, и происходит переполнение стека .

Чтобы избежать переполнения стека. Измените код, чтобы он выглядел следующим образом:

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 голосов
/ 17 декабря 2010

Конструкторы вызываются сверху вниз, то есть если класс A наследуется от B, конструкторы A сначала вызовут родительский конструктор (B).

В вашем случае new SomeClassKiller() рекурсивно вызывает конструктор SomeClass, который, в свою очередь, создает еще один SomeClassKiller ... вот он.

0 голосов
/ 17 декабря 2010
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 навсегда.

...