Как я могу сделать следующий метод подходящим для любого класса, реализующего интерфейс 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);
}
}
}