Корректное переопределение дедушкиного метода, уже реализованного в родительском методе

#java #polymorphism #overriding #decorator

#java #полиморфизм #переопределение #декоратор

Вопрос:

Редактировать: похоже, что моя проблема исходит откуда-то совсем из другого места. Если вы еще не прочитали остальную часть этого раздела, у меня есть a class A , a class B extending class A и a class BDecorator extending 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
 

Поскольку поток является of 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);
    }
}
 

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

Вторая итерация декоратора: переопределение новой функции bar, созданной в 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 from BDecorator никогда не вызывается?

Комментарии:

1. Привет, не могли бы вы также проголосовать за ответ i.stack.imgur.com/Y7YCv.png 🙂

Ответ №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 класса, а затем перенаправляет вызов foo method из B, переданный конструктору BDecorator в вашем случае:

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

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