[英]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
? super
到Comparator
的类型参数,因为比较器是 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.