Почему универсальный метод интерфейса может быть реализован как неуниверсальный в Java?

Допустим, у нас есть несколько тестовых интерфейсов / классов, подобных этому:

abstract class Plant {
    public abstract String getName();
}

interface Eatable { }

class Apple extends Plant implements Eatable {
    @Override
    public String getName() {
        return "Apple";
    }
}

class Rose extends Plant {
    @Override
    public String getName() {
        return "Rose";
    }
}

interface Animal {
    <T extends Plant & Eatable> void eat(T plant);
}

Ты можешь видеть Animal.eat является универсальным методом с ограничениями. Теперь у меня есть мой Human класс как это:

class Human implements Animal {
    @Override
    public void eat(Plant plant) {
    }
}

который компилируется нормально. Ты можешь видеть Human.eat менее ограничен, чем Animal.eat поскольку Eatable интерфейс потерян.

В1: Почему компилятор не жалуется на это несоответствие?

Q2: если Plant&Eatable понижение до Plant приемлем для компилятора, почему жалуется на eat(Object plant)?

2 ответа

Решение

Урок: Генерики Гилада Брача по его словам

public static <T extends Object & Comparable<? super T>> T max(Collection<T> coll)

Это пример задания нескольких границ для параметра типа с использованием синтаксиса T1 & T2 ... & Tn. Известно, что переменная типа с несколькими границами является подтипом всех типов, перечисленных в границах. Когда используется множественная граница, первый тип, упомянутый в границе, используется как стирание переменной типа.

так твой пример <T extends Plant & Eatable> void eat(T plant); будут стерты в void eat(Plant plant); поэтому, когда вы переопределяете его, компилятор не жалуется

Ахмед ответ прав, кстати, если вы хотите ограничить реализацию интерфейса Animal, вы должны объявить это так:

interface Animal<T extends Plant & Eatable>  {
    void eat(T plant);
}

Затем, если вы реализуете интерфейс Animal без предоставления информации о типе, компилятор будет использовать политику наименьшего количества неожиданностей для вывода T как типа Plant. Но если вы предоставите необходимую информацию о типе, компилятор работает нормально.

class Human implements Animal<Rose> // won't compile
class Human implements Animal<Apple> // compile
Другие вопросы по тегам