ООП переполнение стека Java из переопределенного метода - PullRequest
0 голосов
/ 16 октября 2018

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

В качестве примера рассмотрим мой MWE, где RightTriangle расширяет Rectangle, что расширяет Shapes.Метод semiPerimeter() реализуется путем вызова perimeter().

Все хорошо для Rectangle, где работают perimeter() и semiPerimeter().Проблема заключается в perimeter() методе RightTriangle, который переопределяет Rectangle perimeter().При запуске теста я получаю StackOverflowError, потому что semiPerimeter() вызывает perimeter(), что в свою очередь вызывает semiPerimeter().

Почему при вызове super.semiPerimeter() не используется perimeter() из прямоугольного суперкласса?


MWE

Shapes.java

package ShapesPackage;
public abstract class Shapes {
    public abstract double perimeter();
    public double semiPerimeter() {
        return perimeter() / 2;
    }
}

Rectangle.java

package ShapesPackage;
public class Rectangle extends Shapes {
    public double perimeter() {
        return 2 * (3 + 4); //2*(length+height)
    }
}

RightTriangle.java

package ShapesPackage;
public class RightTriangle extends Rectangle {
    public double perimeter() {
        return super.semiPerimeter() + 5;  //half the rectangle perimeter plus some hypotenuse
    }
}

Test.java

package ShapesPackage;
public class Test {
    public static void main(String[] args) {
        Rectangle r = new rectangle();
        System.out.println(r.perimeter());
        System.out.println(r.semiPerimeter());
        RightTriangle t = new rightTriangle();
        System.out.println(t.perimeter());  //Fails
    }
}

Ответы [ 3 ]

0 голосов
/ 16 октября 2018

Вот что происходит:

Вы звоните t.perimeter(), который звонит super.semiPerimeter() -> perimeter() -> super.semiPerimeter() и т. Д. И т. Д. И т. П.

Похоже, вы уже знаете это,Я считаю, что когда вы расширяете класс, если вы создаете метод с той же сигнатурой, что и родительский класс, вы переопределяете его, заставляя любые вызовы переходить к вашему методу переопределения вместо оригинала.perimeter, который абстрактный класс вызывает неявно this.perimeter, а что такое this?Это rightTriangle.Поэтому, когда ваш абстрактный класс видит perimeter, он видит тот, который вы создали с помощью rightTriangle.

0 голосов
/ 16 октября 2018

Почему в вызове super.semiPerimeter() не используется perimeter() из суперкласса прямоугольника?

Поскольку вы вызвали его для объекта rightTriangle, который переопределил perimeter() метод.Для вызова perimiter() не имеет смысла вызывать класс rectangle, поскольку это rightTriangle объект.Из-за этого оба метода постоянно вызывают себя, что приводит к StackOverflowError

0 голосов
/ 16 октября 2018

Ваш метод (t.perimeter ()) вызывает semiPerimeter метод из Shapes класса, который, в свою очередь, снова вызывает perimeter из rightTriangle класса, и это повторяется.

Обратите внимание, что new rightTriangle() в основном означает, что return perimeter() / 2 вызовет perimeter метод из rightTriangle класса.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...