Ошибка StackOverflow при приведении к суперклассу - PullRequest
1 голос
/ 15 июня 2019

Я нашел следующий код в интернете.

 class A {
        public void perform_work() {
            System.out.println("A");
        }
    }
class B extends A {
    public void perform_work() {
        System.out.println("B");
    }
}

class C extends B {
    public void perform_work() {
        ((A) this).perform_work(); // Line 163
    }

    public static void main(String[] args) {
        C c = new C();
        c.perform_work();
    }
}

Этот код компилируется чисто, но выдает ошибку при его запуске:

Exception in thread "main" java.lang.StackOverflowError
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)
    at com.hamzablm.C.perform_work(Main.java:163)

........................................... больше подобных ошибок

Я ожидал, что строка 163 (указанная в приведенном выше коде) вызовет perfom_work(), определенный в классе А. Почему возникла эта ошибка?И как это решить?

Ответы [ 3 ]

8 голосов
/ 15 июня 2019

Если вы хотите, чтобы perfom_work в C выполнялось perfom_work в A, вам нужно изменить его на:

public void perform_work() {
    super.perform_work();
}

И сделать то же самое изменение в B

Как написано в данный момент, он вызывает себя рекурсивно, поэтому никогда не останавливается.

1 голос
/ 15 июня 2019

Код, который вы написали в методе execute_work () в классе C, по сути эквивалентен следующему:

public void perform_work() {
    A someA = this;
    someA.perform_work();
}

, который, как вы, вероятно, знаете, не меняет тип объекта, на который ссылается переменная someA. Это все еще объект типа C, и вызов метода execute_work () для ссылки на него вызовет реализацию из класса C.

Представьте себе следующий сценарий:

public static void perform_more_work(A someA) {
    someA.perform_work();
}

public void perform_work() {
    perform_more_work(this);
}

Должно быть очевидно, какой метод будет вызываться приведенным выше кодом.

1 голос
/ 15 июня 2019

In C in perform_work this является типом передачи от C до A, поэтому вместо этого вызывается perform_work в A, но этот метод переопределяется в C, поэтому он возвращается туда, где еще раз выполняется типизация, и все это происходит снова, пока вы не получите StackOverflowError

Как уже упоминалось в другом ответе, вам нужно использовать super, чтобы решить эту проблему.

...