【问题标题】:How to return the same generic Collection-type with different element-type?如何返回具有不同元素类型的相同通用集合类型?
【发布时间】:2021-11-11 09:49:43
【问题描述】:

我有一个方法,它将集合的元素映射到其他对象并返回包含映射元素的集合。我希望返回的 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&lt;T&gt; 部分不起作用。

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

【问题讨论】:

标签: java generics types


【解决方案1】:

你不能,我不认为,因为例如ArrayList&lt;String&gt;ArrayList&lt;Integer&gt; 本质上是不相关的类型。

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

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

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


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

</* 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.

【讨论】:

  • Java 类型系统很弱:/ 我看不出这两点有何不同。两者都是“如果我给你一个 Collection 的子类 X 的实例,你就会给我一个 X 的实例”。我认为实例化问题很小,因为大多数 Collection 类型都有一个标准的构造函数,所以X.newInstance() 应该大部分都可以工作,如果不是,向那个非常特殊的类型添加一个默认构造函数应该是微不足道的。谢谢你的回答:)
  • “因为大多数集合类型都有”标准Java集合框架类型;但是某些集合类型不是标准 Java 集合框架的一部分,并且没有这样的构造函数(例如 Guava ImmutableList,在答案中使用)。所以,依赖这样一个构造函数的存在意味着它不是一个通用的解决方案。
  • 是的,你是对的。对于我的情况,这似乎是最好的解决方案,因为显然在 Java 中没有通用解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-06-19
  • 1970-01-01
  • 2019-12-18
  • 2016-10-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多