Наследование в интерфейсе - PullRequest
0 голосов
/ 21 мая 2018

У меня есть два интерфейса:

public interface EventListener {

    <T extends Data> T modify(T data);

    public static class Data {

    }
}

И:

public interface ServerInfoEventListener extends EventListener {

    // This works
    @Override ServerInfoData modify(Data data);

    // This doesn't work!
    @Override ServerInfoData modify(ServerInfoData data);

    public static class ServerInfoData extends Data {
        public ServerInfoData(String motd, int playerCount, int maxPlayers) {
            this.motd = motd;
            this.playerCount = playerCount;
            this.maxPlayers = maxPlayers;
        }
        public String motd;
        public int playerCount;
        public int maxPlayers;
    }
}

Как видно из комментариев, modify(ServerInfoData data) не компилируется.Почему нет, и как мне это исправить?ServerInfoData расширяет Data, так что должно работать, верно?

Ответы [ 4 ]

0 голосов
/ 21 мая 2018

Как объявлено в интерфейсе EventListener метод modify требует аргумент типа Data (или любого подкласса)

ServerInfoData modify(ServerInfoData data); принимает аргумент типа ServerInfoData, однако определение в интерфейсе говорит "Он должен принимать все, что имеет суперкласс типа Data ", что означает, что тип аргументов метода в подклассе не соответствует тому, что объявлено в интерфейсе.

Рассмотрим этот пример:

public static class AnotherData extends Data {
    // Whatever
}

public void main() {
    EventListener el = new ServerInfoEventListener() {...};
    el.modify(new AnotherData()); // We have a problem
}

Проблема: Нет реализации метода для обработки AnotherData, но она должна быть, потому что EventListener говорит об этом.ServerInfoData modify(ServerInfoData data) Не могу принять это, потому что AnotherData не является экземпляром ServerInfoData

Надеюсь, это поможет.

0 голосов
/ 21 мая 2018

Вы не можете сузить универсальный тип при переопределении супер-метода.

<T extends Data> T modify(T data);

Этот метод из интерфейса принимает Data и любой подкласс Data.

Но при переопределениинапример:

@Override 
ServerInfoData modify(ServerInfoData data);

Тогда ваш метод не может иметь родственный класс ServerInfoData, который расширяет класс Data, следовательно, он нарушает переопределенный контракт.

0 голосов
/ 21 мая 2018

Я не могу адекватно объяснить конкретную техническую причину, по которой это не сработает, но я могу объяснить исправление.

Ваш интерфейс должен использовать обобщения на уровне класса, а не на уровне метода.Мы также должны вывести Data из EventListener (из-за тупика создания ):

class Data
{
    //...
}

interface EventListener<T extends Data>
{
    T modify(T data);
}

interface ServerInfoEventListener extends EventListener<ServerInfoEventListener.ServerInfoData>
{
    @Override ServerInfoData modify(ServerInfoData data);

    class ServerInfoData extends Data {
        //...
    }
}

class ServerInfoEventListenerImpl implements ServerInfoEventListener
{
    @Override
    public ServerInfoData modify(final ServerInfoData data)
    {
        return null;
    }
}
0 голосов
/ 21 мая 2018
@Override ServerInfoData modify(ServerInfoData data)

не работает, потому что фактически не переопределяет EventListener.modify, так как он не будет принимать любой другой подкласс Data, кроме ServerInfoDataего подклассы).

Вам нужно либо обработать все Data типы, либо сделать сам интерфейс универсальным, а не только один метод:

public interface EventListener<T extends Data> {
    T modify(T data);
}

public interface ServerInfoEventListener extends EventListener<ServerInfoData> {
    @Override ServerInfoData modify(ServerInfoData data);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...