首页 > 解决方案 > 如何返回具有不同元素类型的相同通用集合类型?

问题描述

我有一个方法,它将集合的元素映射到其他对象并返回包含映射元素的集合。我希望返回的 Collection 与输入 Collection 具有相同的 Collection 类型,但具有不同的元素类型。我的方法看起来像这样:

<E extends OriginalElement, T extends TargetElement,
 C extends Collection<E>, R extends C<T>> R map(C elementsToMap) {
    // snip
}

显然这部分R extends C<T>不起作用。

如何将返回类型指定为Collection与 Type相同的子类C,但使用元素类型T而不是E

标签: javagenericstypes

解决方案


你不能,我不认为,因为例如ArrayList<String>ArrayList<Integer>本质上是不相关的类型。

另外,当您说“相同的通用集合类型”时,您的意思是:

  • "如果我给你一些 ArrayList 的子类,你会给我一个 java.util.ArrayList 的实例"; 或者
  • “如果我给你一个ArrayList 的特定子类,你会给我一个与 ArrayList 相同的特定子类的实例”?

这不仅很难,因为通常您不知道如何实例化任意子类,您可能无法创建这样的实例,例如,如果输入是一个IntegerArrayList (extends ArrayList<Integer>),并且您想将元素映射到字符串。因此,虽然您可以java.util.ArrayList<String>在这种情况下返回 a,但您无法获得通用解决方案,因为您需要了解“在这种特定情况下要实例化哪种类型”。


我将做出一个未量化的断言,即少数集合类型可以处理大多数情况。因此,为这些特定类型提供重载:

</* type variables */> ArrayList<T> map(ArrayList<E> input) { ... }

</* type variables */> HashSet<T> map(HashSet<E> input) { ... }

</* type variables */> ImmutableList<T> map(ImmutableList<E> input) { ... }

// etc.

然后为其他情况提供一个通用方法,并让调用者指定他们想要的集合类型:

</* type variables */> Stream<T> map(Collection<E> input) { ... }

然后从具体方法中调用通用方法:

</* type variables */> ArrayList<T> map(ArrayList<E> input) {
  return map((Collection<E>) input).collect(toCollection(ArrayList::new));
}

// etc.

推荐阅读