簡體   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