[英]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.