Правильно переопределить метод Grandparent, уже реализованный в методе Parent

Обновлено: похоже, что моя проблема исходит совершенно из другого места. Если вы еще не прочитали остальную часть этой темы, у меня есть class A, class B расширение class A и class BDecorator расширение class B. Я думал, что не могу переопределить конкретную функцию из class B в моем декораторе, но после нескольких дней тестирования и испытаний оказалось, что моя проблема связана с тем, как я создаю потоки. class A реализует Runnable и имеет функцию listen() создания потока и вызова start(). Создаю тему с аргументом this. Это важно, потому что в определенное время создания потока this будет типа class B.

new BDecorator(new B());
//             ^ The thread is created with the creation of this object, before it can be passed as an argument to BDecorator

Поскольку поток относится к class B, он будет вызывать foo() из B object, использованного для его создания.

Хотя я бы не сказал, что эта проблема решена, это уже совсем другая проблема, не имеющая отношения к полиморфизму. Спасибо @akuzminykh, @dreamcrash и @Itay Dumay за помощь в решении этой проблемы, а также за правильное форматирование этого поста.


У меня есть реферат class A, реализующий Runnable. A делает следующее в методе run() (сокращенно):

final public void run() {
    try {
        this.foo(message);
    }
    //...
}

Class A также имеет следующую функцию:

protected abstract void foo(String message);

Первая итерация декоратора: переопределение функции foo.

Затем я создал класс B, который не является абстрактным, делая следующее:

public class B extends A {
    // Constructors and getters/setters go here
    
    protected void foo(String message) {
        System.out.println(message);
    }
}

Этот код работает нормально. С тех пор я решил добавить в B функции, которые не изменят работу всего приложения, создав декоратор.

public class BDecorator extends B {
    B decoratedB;
    
    public BDecorator(B b) {
        this.decoratedB = b;
    }
    
    @Override
    protected void foo(String message) {
        this.decoratedB.foo("Testing a foo decorator: " + message);
    }
}

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

Вторая итерация декоратора: переопределение новой функции панели, созданной в B.

Что странно, так это то, что у меня также есть метод, написанный на B вот так:

public class B extends A {
    // Constructors and getters/setters go here

    protected void foo(String message) {
        System.out.println(message);
    }

    protected void bar(String message) {
      System.out.println(message);
    }
}

bar не существует нигде в class A. Я могу подтвердить, что программа действительно вызовет BDecorator::bar() со следующим переопределением (когда я ставлю точки останова):

public class BDecorator extends B {
    B decoratedB;
    
    public BDecorator(B b) {
        this.decoratedB = b;
    }
    
    @Override
    protected void foo(String message) {
        this.decoratedB.foo("Testing a foo decorator: " + message);
    }

    // This method wasn't in A. It was only present in B, and for some reasons it gets called.
    @Override
    protected void bar(String message) {
        this.decoratedB.bar("Testing a bar decorator: " + message);
    }
}

Вот что происходит в моей основной:

B firstTestSubject = new BDecorator(new B(...));
BDecorator secondTestSubject = new BDecorator(new B(...));

// Let's test both foo functions
firstTestSubject.foo("Hello world!");
secondTestSubject.foo("Hello world!");

// Now let's test both bar functions
firstTestSubject.bar("Goodbye world!");
secondTestSubject.bar("Goodbye world!)";

Выход:

> Hello world!
> Hello world!
> Testing a bar decorator: Goodbye world!
> Testing a bar decorator: Goodbye world!

Вопрос: почему никогда не вызывается foo override из BDecorator?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
0
173
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Возникает вопрос: почему переопределение foo из BDecorator никогда не вызывается?

Это называется:

Из класса BDecorator добавьте следующее Statement:

@Override
protected void foo(String message) {
    System.out.println("Do I even exist?");
    this.decoratedB.foo("Testing a foo decorator: " + message);
}

выход:

Do I even exist?
Testing a foo decorator: Hello world!
Do I even exist?
Testing a foo decorator: Hello world!
Testing a bar decorator: Goodbye world!
Testing a bar decorator: Goodbye world!

Вызывается метод foo из класса BDecorator, а затем перенаправляет вызов в foomethod из B, переданный конструктору BDecorator в вашем случае:

new BDecorator(new B(...));

и экземпляр объекта из класса B.

Другие вопросы по теме