Создание коллекции для возврата из универсального метода - PullRequest
0 голосов
/ 21 декабря 2018

Предостережение: Да, я знаю, что я мог бы заставить вызывающие методы использовать Collection, а не подкласс или привести коллекцию или несколько других вещей.И, вероятно, сделаю это в ожидании ответов.Но мне любопытно, возможно ли это, и мое Google-фу никуда меня не приведет.: -)

Итак, у меня есть метод, у которого в качестве параметра указан либо Set, либо List, и он возвращает один и тот же (и, да, есть другие подклассы Collection, но ониэти два я увижу).Поэтому я попытался использовать дженерики:

private <T extends Collection<String>> T doStuff(T input) {
  T output = (input instanceof List) 
    ? new ArrayList<String>() 
    : new HashSet<String>();
  // do stuff to fill output from input
  return output;
}

В этой версии красные чернила, которые говорят, что я не могу преобразовать ArrayList в T. Я попробовал варианты этого без удачи.Есть мысли?

РЕДАКТИРОВАТЬ: Спасибо за юмористическое любопытство.Я, конечно, буду использовать что-то более простое, например, просто вернуть коллекцию, но хорошо знать, что это за проблема, для дальнейшего использования.

Ответы [ 3 ]

0 голосов
/ 21 декабря 2018

Если вы действительно способны вернуть коллекцию, это означает, что вам нужен только интерфейс коллекции, и вам не нужны компромиссы между скоростью и размером различных подклассов коллекции.

Если это действительно так, то не имеет значения, возвращаете ли вы List или Set, независимо от того, с кем вы вызывались.Так что просто сделайте это:

private Collection doStuff(Collection input) {
  // do stuff to fill output from input
  return new ArrayList(input);
  // or, return new HashSet(input);
}

Если вы или ваши абоненты действительно заботитесь о методах (или гарантиях скорости / размера) определенных подклассов Collection, то вам придется перегружать фактические подклассыпредставляет интерес.

Обратите внимание, что разрешение перегрузки определяется во время компиляции с использованием статических (опорных) типов, а не динамических типов, на которые фактически указываются во время выполнения.

0 голосов
/ 21 декабря 2018

Пусть S extends Collection<String> будет абстрактный тип коллекции, которую вы хотите вернуть из вашего метода, т. Е. List или Set.

Пусть C extends S будет типом времени выполнения длявозвращенный результат, т.е. ArrayList или HashSet.

Чтобы получить экземпляр C во время компиляции, вам придется явно предоставить экземпляр Class<C> в качестве аргумента.

Итак, метод становится следующим:

public <S extends Collection<String>, C extends S> S doStuff(S input, Class<C> clazz) throws Exception {
    C output = clazz.newInstance();
    // do stuff to fill output from input
    return output;
}

Вы сможете вызывать эти методы с помощью:

List<String> list = new ArrayList<String>() {{ add("Hello"); }};
doStuff(list, ArrayList.class);

Set<String> set = new HashSet<String>() {{ add("World"); }};
doStuff(set, HashSet.class);

Конечно, вы должны позаботиться о проверенномисключения, которые могут быть вызваны из обратного вызова clazz.newInstance().

0 голосов
/ 21 декабря 2018

Чтобы избежать ошибки компиляции, вы должны создать экземпляр объекта типа T, который невозможен в Java из-за стирания типа.Я предлагаю использовать два перегруженных метода вместо общего.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...