gpt4 book ai didi

java - 使用泛型转换 Java 集合的正确方法签名

转载 作者:行者123 更新时间:2023-11-30 07:04:28 26 4
gpt4 key购买 nike

我正在努力使用泛型来确定转换 Collection 的方法的正确方法签名。类型 A 到指定类型 B 的集合中。例如,我有一个 ArrayList A 的,我希望该方法返回 LinkedList到目前为止,我已经想出了

<A, B, C extends Collection<B>> C mapCollection(
final Iterable<A> source,
final Class<B> destinationClass,
final Class<C> collectionClass)

但是,如果我编写以下代码:

ArrayList<TypeA> listOfA = getList();
LinkedList<TypeB> listOfB = mapCollection(listOfA, TypeB.class, LinkedList.class);

编译器发出有关 mapCollection 的警告返回LinkedList 。显然,它使用 LinkedList.class确定 C 类型的参数,而不是看到 C延伸Collection<B>

如果我这样做,事情会变得更有趣

List<TypeB> = mapCollection(listOfA, TypeB.class, LinkedList.class);

因为这样,编译器会给出类型不匹配错误,cannot convert from ArrayList to List<T> 。有趣的是,这只发生在 Eclipse 中,javac对这段代码非常满意。当然,我必须使用@SuppressWarnings("unchecked")我宁愿避免。

关于如何解决这个问题有什么想法吗?或者说这是不可能的?

最佳答案

正如其他人所指出的,您遇到了由删除引起的 Java 泛型的限制。具体来说,类文字 LinkedList.class类型为Class<LinkedList> 。它只能表示原始类型,例如 LinkedList ;它不能表示参数化类型,例如 LinkedList<TypeB> .

如果您有 Class<LinkedList<TypeB>> 的实例然后它就可以工作了:

Class<LinkedList<TypeB>> clazz = ... ;
List<TypeB> listOfB = mapCollection(listOfA, TypeB.class, clazz);

不幸的是,获得这样的类实例是笨拙且困难的。您可以通过 raw 进行转换来获取它:

@SuppressWarnings("unchecked")
Class<LinkedList<TypeB>> clazz = (Class<LinkedList<TypeB>>) (Class) LinkedList.class;

但这并不比你现在拥有的更好。

您可以研究诸如 Guava 的 TypeToken 之类的技术。类(截至 Guava 20 仍处于测试阶段)。背景请参见原文"Super Type Tokens"来自 Neal Gafter 及其 limitations 的更新.

<小时/>

使用类型标记的主要问题是它依赖于被调用者(本例中为 mapCollection)创建目标类实例的能力。按照惯例,Java 的集合有一个无参数构造函数,因此这很简单,可以反射调用。但是,如果需要进行一些定制,例如指定初始容量或用于排序的比较器,该怎么办?使用类型标记时处理这些问题非常困难。

Java 8 的方法是传递一个函数 -- a Supplier -- 创建目标实例。这允许调用者指定类型以及任何专门的构造函数参数,同时让被调用者确定何时发生创建。为此,您需要重写方法签名,如下所示:

<A, B, C extends Collection<B>> C mapCollection(
final Iterable<A> source,
final Supplier<C> supplier) { ... }

并且您可以使用 lambda 表达式来调用它:

List<TypeB> listOfB = mapCollection(listOfA, () -> new LinkedList<TypeB>());

或使用方法引用:

List<TypeB> listOfB = mapCollection(listOfA, LinkedList::new);

注意 LinkedList 的类型参数在方法引用案例中正确推断。

作为奖励,mapCollection实现不需要处理任何反射。它需要做的就是调用 supplier.get() .

附注不要使用LinkedList .

关于java - 使用泛型转换 Java 集合的正确方法签名,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40376798/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com