Переопределить переменную с типом подкласса - PullRequest
0 голосов
/ 23 января 2019

У меня есть класс, который имеет интерфейс слушателя. Я хочу создать подкласс с интерфейсом слушателя, являющимся типом подкласса. Например:

interface OnSadListener {
    void imSad();
}

interface OnCryingListener extends OnSadListener {
    void imCrying();
}

class Person {
    OnSadListener listener;

    void setListener(OnSadListener listener){
        this.listener = listener;
    }
}

class Baby extends Person {
    OnCryingListener listener; // I want it to override the original one in Person

    void cry(){
        listener.imSad();
        listener.imCrying();
    }
}

void doIt(){
    Baby michael = new Baby();

    michael.setListener(new OnCryingListener() {
        @Override void imSad(){
            System.out.print("I'm sad");
        }

        @Override void imCrying(){
            System.out.print("Wahhhhhh!");
        }
    });

    michael.cry(); // the imCrying funtion is empty (setListener setted Person's listener and not Baby's)
}

Я знаю, Baby.setListener(new OnCryingListener(){...}); будет работать, потому что OnCriedListener является подклассом OnSadListener. Но тогда я бы не смог позвонить imCrying() или он был бы пуст.

Есть ли способ для OnCryingListener listener "переопределить" Person OnSadListener listener?

Ответы [ 2 ]

0 голосов
/ 23 января 2019

Поля НЕ "переопределены" в Java.Только методы переопределяются.

Поскольку вы предполагаете, что поля переопределяются, в этом примере вы ожидаете, что в объекте Baby существует только одно поле listener.И вы ожидаете, что это единственное поле будет установлено при вызове michael.setListener().

Но в действительности в объекте Baby есть 2 поля.При вызове michael.setListener() устанавливается только поле, объявленное в классе Person.

0 голосов
/ 23 января 2019

Вам необходимо переопределить метод setListener(OnSadListener) в классе Baby, потому что вы никогда не устанавливаете слушателя.

class Baby extends Person {
    OnCryingListener listener;

    @Override
    void setListener(OnSadListener listener) {
        this.listener = (OnCryingListener) listener;
    }

    void cry() {
        listener.imSad();
        listener.imCrying();
    }
}

Более полным примером является следующий ...

class Person {
    protected OnSadListener listener; // Make it protected or add accessor/mutators

    void setListener(OnSadListener listener) {
        this.listener = listener;
    }
}

Сделав listener защищенным, вы можете повторно использовать Person class 'OnSadListener.Вам просто нужно привести слушателя к OnCryingListener для вызова метода imCrying().

class Baby extends Person {
    @Override
    void setListener(OnSadListener listener) {
        this.listener = (OnCryingListener) listener;
    }

    void cry() {
        listener.imSad();
        ((OnCryingListener) listener).imCrying(); // Cast here
    }
}

Обновление

Если вы хотите использовать дженерики, вы можете удалитьпотребность в кастинге.

public class Person <T extends OnSadListener> {
    protected T listener;

    public void setListener(T listener) {
        this.listener = listener;
    }
}

Теперь вы можете сказать Baby, с каким типом слушателя имеет дело.

public class Baby extends Person<OnCryingListener> {
    @Override
    public void setListener(OnCryingListener listener) {
        this.listener = (OnCryingListener) listener;
    }

    public void cry() {
        listener.imSad();
        listener.imCrying(); // No need to cast
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...