Как я могу сделать следующий метод подходящим для любого класса, реализующего интерфейс String getValue()? Возможно ли это с дженериками?
private static void findUniqueEntriesInList(List<ColValueObject> list1,
List<ColValueObject> list2,
List<ColValueObject> result) {
for (ColValueObject l1 : list1) {
boolean found = false;
for (ColValueObject l2 : list2) {
if (l1.getValue().equals(l2.getValue())) {
found = true;
break;
}
}
if (!found) {
result.add(l1);
}
}
}
С:
class ColValueObject implements GetValueToStringObject {
private String base;
private String value;
// boilerplate omitted
}
Я мог бы создать этот интерфейс и метод:
public interface GetValueToStringObject {
String getValue();
}
И:
private static void findUniqueEntriesInListUsingGenerics(List<GetValueToStringObject> list1,
List<GetValueToStringObject> list2,
List<GetValueToStringObject> result) {
for (GetValueToStringObject l1 : list1) {
boolean found = false;
for (GetValueToStringObject l2 : list2) {
if (l1.getValue().equals(l2.getValue())) {
found = true;
break;
}
}
if (!found) {
result.add(l1);
}
}
}
Проблема в том, что я не могу напрямую вызвать метод следующим образом:
findUniqueEntriesInListUsingGenerics(list1, list2, result);
Мне не совсем понятно, чего вы пытаетесь достичь, но очевидно, что List<GetValueToStringObject> не является List<ColValueObject> и наоборот, и, учитывая, что между GetValueToStringObject и ColValueObject нет отношений реализации (или расширения), в его нынешнем виде ваш метод не может работать .
Делая некоторые разумные предположения, я думаю, вам понадобится ColValueObject для реализации GetValueToStringObject. Затем вы можете использовать дженерики с <T extends GetValueToStringObject>, чтобы делать то, что хотите:
class ColValueObject implements GetValueToStringObject {
private String base;
private String value;
@Override
public String getValue() {
return value;
}
// boilerplate omitted
}
Затем реализуйте свой метод как:
private static <T extends GetValueToStringObject> void findUniqueEntriesInListUsingGenerics(
List<T> list1, List<T> list2, List<T> result) {
for (T l1 : list1) {
boolean found = false;
for (T l2 : list2) {
if (l1.getValue().equals(l2.getValue())) {
found = true;
break;
}
}
if (!found) {
result.add(l1);
}
}
}
При этом все списки должны иметь один и тот же общий тип, более гибкое решение см. В конце ответа.
Кроме того, я думаю, что параметр result не принадлежит вашему методу и что он должен возвращать List<T>, созданный в методе. Например:
private static <T extends GetValueToStringObject> List<T> findUniqueEntriesInListUsingGenerics(
List<T> list1, List<T> list2) {
List<T> result = new ArrayList<>();
// ... code above
return result;
}
В качестве альтернативы, если вы хотите, чтобы list1, list2 и result имели разные типы, вы можете использовать:
private static <T extends GetValueToStringObject> void findUniqueEntriesInListUsingGenerics(
List<T> list1,
List<? extends GetValueToStringObject> list2,
List<? super T> result) {
for (T l1 : list1) {
boolean found = false;
for (GetValueToStringObject l2 : list2) {
if (l1.getValue().equals(l2.getValue())) {
found = true;
break;
}
}
if (!found) {
result.add(l1);
}
}
}
Здесь list1 определяется как фактический тип, list2 может быть любым списком типов, расширяющих (реализующих) GetValueToStringObject, а result может быть списком любого суперкласса/суперинтерфейса T.
Например, если list1 — это List<ColValueObject>, то result может быть List<ColValueObject>, List<GetValueToStringObject> или List<Object>, а list2 может быть List<GetValueToStringObject>, List<ColValueObject> или List<SomeOtherTypeImplementingGetValueToStringObject>.
Ниже приведен еще один вариант, но он ограничивает тип result только List<GetValueToStringObject и List<Object>, что, на мой взгляд, менее полезно, чем предыдущее решение:
private static void findUniqueEntriesInListUsingGenerics(
List<? extends GetValueToStringObject> list1,
List<? extends GetValueToStringObject> list2,
List<? super GetValueToStringObject> result) {
for (GetValueToStringObject l1 : list1) {
boolean found = false;
for (GetValueToStringObject l2 : list2) {
if (l1.getValue().equals(l2.getValue())) {
found = true;
break;
}
}
if (!found) {
result.add(l1);
}
}
}