繁体   English   中英

Java 用于排序双嵌套 generics 数组的比较器

[英]Java comparator for sorting double-nested generics array

对于 Java 17,我想根据某些标准比较 map 条目,其中 map 条目是与某些值关联的 Java 类,如下所示:

Comparator<Map.Entry<Class<?>, Integer>> MY_COMPARATOR =
    new Comparator<Map.Entry<Class<?>, Integer>>() { … }

后来我有一个类列表及其关联值的列表(无论是计数、memory 大小还是其他)。 不同之处在于我的代码非常精炼(开玩笑),以至于我碰巧知道所有这些类都是从FooBar扩展而来的:

List<Map.Entry<Class<? extends FooBar>, Integer>> foobarValues = new ArrayList<>();

现在我只想使用MY_COMPARATOR对那些 map 条目进行排序(以查找最小/最大的类、最常遇到的类或MY_COMPARATOR用作其标准的任何内容)。 但这不起作用:

java.util.Collections.sort(foobarValues, MY_COMPARATOR);

Java(实际上是 Eclipse 2022-09)告诉我:

The method sort(List<T>, Comparator<? super T>) in the type Collections is not applicable for the arguments (List<Map.Entry<Class<? extends FooBar>,Integer>>, Comparator<Map.Entry<Class<?>,Integer>>)

我已经与 Java generics 合作了很长时间,我对正在发生的事情的最好的简化解释是? super T Collections.sort()中的? super T “隐藏”了 generics 的下层,那? super Map.Entry<Class<?>> ? super Map.Entry<Class<?>>? super Map.Entry<Class<? extends FooBar>> ? super Map.Entry<Class<? extends FooBar>> ? super Map.Entry<Class<? extends FooBar>> (但是,真的吗?。)实际上我的头脑无法完全理解问题的全部复杂性。

但是假设我不太关心这个问题; 我只想让代码在没有警告的情况下工作。 你和我都知道比较器可以与任何可能存在的 class 一起工作,所以它永远不会导致ClassCastException并且永远不会造成堆污染,它甚至永远不会在晚上偷偷溜进你的房子并杀死你的竹子植物。

我如何告诉 Java 我可以使用这个比较器? 这不起作用:

Collections.sort(foo, (Comparator<Map.Entry<Class<? extends FooBar>, Integer>>)MY_COMPARATOR);

我很乐意投射正在排序的列表,但这也不起作用:

Collections.sort((List<Map.Entry<Class<?>, Integer>>)foo, MY_COMPARATOR);

确实有效!

Collections.sort(foo, (Comparator<Map.Entry<Class<? extends FooBar>, Integer>>)(Object)comparator);

但是要使用它,我必须添加@SuppressWarnings("unchecked")和 Java 17 javac with -Xlint:all仍然会抱怨,而且我觉得使用它很脏。

只要 javac lint 仍然没有抱怨,我就会满足于一些允许我使用@SuppressWarnings("unchecked")抑制警告的解决方法。 但是中间转换为Object对我来说太过分了,无法接受。

我应该做什么?

我建议您通过应用PECS原则声明比较器。 它应该具有以下类型:

Comparator<Map.Entry<? extends Class<?>, Integer>>

Map.Entry的两种类型参数。条目应该有? extends ? extends (虽然只有第一个就足以修复错误)因为 map 条目是其键和值类型的生产者。

您还可以添加? super ? superComparator的类型参数,因为比较器是 map 条目的消费者,但这里不需要,因为它实际上已经写在sort的方法签名中。

void sort(Comparator<? super E> c)

之后,你可以写:

foobarValues.sort(MY_COMPARATOR);

如果您无法更改MY_COMPARATOR的类型,让编译器“闭嘴”的一种方法是首先转换为Object

(Comparator<Map.Entry<Class<? extends FooBar>, Integer>>) (Object) MY_COMPARATOR

Object转换为参数化类型是未经检查的转换,这大概就是您要查找的内容。

据我所知,这种未经检查的转换是安全的,因为 map 条目不能用作其密钥类型的使用者。 您只能获取它的密钥,而不能设置它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM