Я пытаюсь отфильтровать список объектов, реализующих интерфейс. И я пытаюсь создать общий метод для всех классов.
Что-то вроде:
interface SomeInterface {
String getFlag();
}
class SomeObject implements SomeInterface {
public String getFlag() {
return "X";
}
}
List<SomeObject> someObjectList = new ArrayList<>();
// Compilation error here
List<SomeObject> filterList = filterGenericList(someObjectList, "X");
private List<?> filterGenericList(List<? extends SomeInterface> objects, String flag) {
return objects.stream()
.filter(it -> it.getFlag().equals(flag))
.collect(Collectors.toList());
}
Как убежать от ошибки компиляции?
Incompatible types.
Found: 'java.util.List<capture<?>>',
Required: 'java.util.List<SomeObject>'
Я знаю это. Я пытаюсь получить способ вернуть список моего объекта, используя интерфейс, чтобы не создавать много методов (по одному на класс, реализующий интерфейс)
Когда вы возвращаете List<?>
, это означает, что метод возвращает список неизвестного типа. Java не знает, что это тот же тип списка, что и входной список. Чтобы сигнализировать об этом, создайте общий тип T
и сделайте входной и выходной списки List<T>
.
private <T extends SomeInterface> List<T> filterGenericList(List<T> objects, String flag) {
return objects.stream()
.filter(it -> it.getFlag().equals(flag))
.collect(Collectors.toList());
}
Неограниченный подстановочный знак<?>
, также называемый неизвестный тип, — это способ сообщить компилятору, что общий тип нельзя предсказать, и поэтому компилятор не позволит присвоить список неизвестный тип списку SomeObject
, потому что невозможно гарантировать, что это назначение безопасно. .
Если у вас есть список объектов, принадлежащих к разным классам, реализующим SomeInterface
, чтобы различать их, вы можете явно передать экземпляр целевого класса Class<T>
в метод в качестве аргумента.
Похоже, вы пытаетесь заново изобрести тот же механизм, используя метод getFlag()
. Это не выглядит надежным, потому что ничто не может помешать вам сделать опечатку или случайно реализовать getFlag()
в двух разных классах таким образом, чтобы возвращалось одно и то же значение.
private <T extends SomeInterface> List<T> filterGenericList(List<? extends SomeInterface> objects,
Class<T> targetClass) {
return objects.stream()
.filter(it -> targetClass.isAssignableFrom(it.getClass()))
.map(targetClass::cast)
.collect(Collectors.toList());
}
во-первых, List<?> не содержит никакой информации о типе. Вы ожидаете список SomeObject, но ваш метод просто возвращает список любого типа.
Для достижения вашей цели вы должны определить свой метод фильтра как
private static <T extends SomeInterface> List<T> filterGenericList(List<T> objects, String flag)
Таким образом вы гарантируете, что возвращаемый список имеет тот же тип, что и входной список.
Почему вы ожидаете, что результатом
filterGenericList
будетList<SomeObject>
? Ваш метод не говорит об этом, он говорит, что возвращает список что-либо.