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