Как сделать метод подходящим для классов, реализующих интерфейс?

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
0
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне не совсем понятно, чего вы пытаетесь достичь, но очевидно, что 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);
        }
    }
}

Другие вопросы по теме