Начал разбираться с предикатами и дженериками. И вот у меня есть вот такой вот статический метод:
public static <T> int findFirst(List<T> list, int begin, int end, Predicate<? extends T> p){
for(int i = begin; i <= end; i++)
if(p.test(list.get(i)))
return i;
return -1;
}
Но среда разработки выдает ошибку
T cannot be converted to capture#1 of ? extends T
Не могу понять почему, ведь означает класс Т и его потомки, почему p.test() не принимает элемент листа
Предположим, у нас имеется иерархия классов:
class K { public byte k_value; } // суперкласс для T
class T : K { public int t_value; } // T унаследован от K
class Q : T { public long q_value; } // Q унаследован от T
Когда мы пишем параметр Predicate<? extends T>, это означает, что можно в этот параметр передать методы со следующими сигнатурами:
bool ConditionT(T value);
bool ConditionQ(Q value);
т.е. параметр передаваемого метода должен иметь тип T или тип любого потомка T (в данном случае подходит Q).
Предположим, в ваш метод findFirst мы передали последний вариант: ConditionQ.
Что произойдёт в этом случае? А получится при вызове p.test() попытка передать объект типа T в том месте, где требуется тип Q. В результате получим ошибку приведения типов, что логично: в конкретно данном примере, у объекта Q можно ожидать наличие поля q_value, а объект T его не содержит - так что передавать нельзя.
Когда же пишем параметр Predicate<? super T>, это означает, что можно в этот параметр передать методы со следующими сигнатурами:
bool ConditionK(K value);
bool ConditionT(T value);
т.е. параметр передаваемого метода должен иметь тип T или тип любого предка T (в данном случае подходит K).
Предположим, в ваш метод findFirst мы передали первый вариант: ConditionK.
В этом случае, при вызове p.test() имеется попытка передать объект типа T в том месте, где требуется тип K. Попытка будет успешной, поскольку класс T является производным от K и гарантированно содержит в себе интерфес типа K. В конкретно данном примере можно говорить о том, что не только объект типа K содержит поле k_value, но и объект типа T тоже (в силу наследования).
Например, в качестве Т передается Person, а (? extends Person) будет Student, у которого есть поля, которых нет у Person, но в методе test() надо именно по этим полям задать логику проверки. Как быть?
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости