Почему общий метод интерфейса может быть реализован как не общий для 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 потерян.

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

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

Ответы

Ответ 1

Урок: Generics by Gilad Bracha  по его словам

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

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

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

Ответ 2

Ответ Ахмеда прав, между прочим, если вы хотите ограничить реализацию интерфейса 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