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