Реализация общего метода с верхним ограничением - PullRequest
0 голосов
/ 08 ноября 2019

У меня проблемы с построением несколько круговой общей конфигурации. Мне нужен интерфейс "состояния", который обеспечивает геттер для общего интерфейса "контейнер". Контейнерный интерфейс в его методах должен принимать общее «состояние» в качестве одного из параметров. Я пробовал различные варианты (действительно круговые параметры универсального класса, различные варианты ниже), но то, что у меня есть ниже, является наиболее близким к тому, что мне нужно:

interface Container<K> {
    <C extends Container<K>,S extends State<K,C>> C setData(K key, Object val,S state);
}

interface State<K,C extends Container<K>>{
    C getContainer();
}

class BasicContainer<K> implements Container<K> {
    public <C extends BasicContainer<K>, S extends State<K,C>> C setData(K key, Object val, S state) { return this;}
}

class BasicState<K> implements State<K,BasicContainer<K>> {
    BasicContainer<K> container = new BasicContainer<K>();
    public BasicContainer<K> getContainer(){
        return container;
    }
}

Увы, компилятор дает знаменитыйmethods have same erasure yet neither overrides the other для метода BasicContainer. Я считаю, что это потому, что хотя C extends BasicContainer<K> является подтипом C extends Container<K>, S extends State<K,C> является не подтипом S extends State<K,C> в Container<K>.

Любые предложения о том, каквыполнить желаемой конфигурацией?

Обновление Мне понадобятся другие реализации Container, которые также должны работать с реализацией State, но реализация State не будет возвращать эти реализации,Вот где циклические параметры класса потерпели неудачу.

1 Ответ

0 голосов
/ 08 ноября 2019

Похоже, C должен быть параметром типа на интерфейсе Container, например K.

В общем, если Foo является супертипом Bar, Bar не может добавить дополнительные ограничения к параметрам универсального типа для методов из Foo. Это просто следует из принципа подстановки Лискова: любой Bar должен быть в состоянии использоваться для , для чего можно a Foo.

Ограничение C extends BasicContainer<K> в параметрах типаиз BasicContainer.setData, когда Container.setData имеет только ограничение C extends Container<K>, особенно нарушает это правило.

Вместо этого вы можете использовать верхнюю границу C в качестве параметра типа для Container,и установите для него другое значение в BasicContainer.

. Это может выглядеть следующим образом:

interface Container<K, C extends Container<K, C>> {
    <S extends State<K,C>> C setData(K key, Object val,S state);
}
class BasicContainer<K> implements Container<K, BasicContainer<K>> { ... }

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

interface Container<K, C extends Container<K, C>> {
    <C2 extends C, S extends State<K,C>> C2 setData(K key, Object val,S state);
}
class BasicContainer<K> implements Container<K, BasicContainer<K>> { ... }

(хотя прямо, вторая версия почти наверняка не то, что вы хотите).

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