[英]How to tell Java that two wildcard types are the same?
我編寫了一個小型列表排序器,該排序器通過使用Key
對象以可比較的形式從對象中提取特定的“ key”來工作。 然后,排序器根據所有鍵依次對列表進行排序。
排序器可以使用對給定類型的對象起作用的任何鍵集進行排序。 每個鍵都可以處理一種類型的對象,並且始終返回相同類型的可比較值。
class Sorter {
public interface Key<T, V extends Comparable<V>> {
public V get(T t);
}
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final Comparable av = key[i].get(a), bv = key[i].get(b);
final int cmp = av.compareTo(bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}
}
因此,例如,您可能有一個JSONStringKey
提取一個String
(是Comparable
),並且您可能有一個單獨的JSONNumericKey
提取了Double
(也是Comparable
)。 永遠不會比較來自兩個不同鍵的值,但是將比較兩個不同對象上的相同鍵。
class JSONStringKey extends Sorter.Key<JSONObject, String> {
final String key;
JSONStringKey(String key) {this.key = key;}
public String get(JSONObject o) {return o.optString(key);}
}
class JSONNumericKey extends Sorter.Key<JSONObject, Double> {
final String key;
JSONNumericKey(String key) {this.key = key;}
public Double get(JSONObject o) {return o.optDouble(key);}
}
...
// sort by price descending then name ascending
final Key<JSONObject, ?> keys[] = { new JSONNumericKey("price"), new JSONStringKey("name") };
sort(list, keys, new int[]{-1, 1});
Java警告排序器中的這一行:
final Comparable av = key[i].get(a), bv = key[i].get(b);
它警告av
和bv
聲明為原始類型: Comparable
而不是Comparable<?>
。 他們是。 但是,如果我將類型更改為Comparable<?>
,則下一行av.compareTo(bv)
失敗,因為兩個不同的Comparable<?>
不一定是同一類型。 在我的特定實現中,它們將是,但是我不知道如何將其表達給類型系統。
如何告訴類型系統av
和bv
具有完全相同的類型? 我無法通過提供特定類型(例如Comparable<String>
)來“修復”它,因為在我的示例中,循環中的第一個鍵返回String
(實現Comparable<String>
),而循環中的第二個鍵返回Double
(實現Comparable<Double>
)。
我可以在key[i].get()
行上編寫@SuppressWarnings("rawtypes")
,在av.compareTo(bv)
行上@SuppressWarnings("unchecked")
,但是我想盡可能地檢查類型可能。
編輯:感謝davmac的回答,創建一個修復特定可比類型的中間方法可以正常工作:
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final int cmp = compareKey(key[i], a, b);
if (cmp != 0) return cmp * dir[i];
}
}
private <V extends Comparable<V>> compareKey(Key<T, V> key, T a, T b) {
final V av = key.get(a), bv = key.get(b);
return av.compareTo(bv);
}
您需要使用類型參數來說明兩個“未知”類型是相同的。 我認為也許您應該將方法簽名從以下位置更改:
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[])
至
static <T,U> void sort(List<T> data, final Key<T,U> key[], final int dir[])
但是,我認為這不適用於您的完整示例,因為鍵中的元素不是同一類型:
// sort by price descending then name ascending
final Key<JSONObject, ?> keys[] = { new JSONNumericKey("price"), new JSONStringKey("name") };
sort(list, keys, new int[]{-1, 1});
因此,您可以將排序器中的相關部分提取到通用方法中:
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final Comparable<?> av = key[i].get(a), bv = key[i].get(b);
final int cmp = doCompareTo(av, bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
private <U extends Comparable<U>> int doCompareTo(U a, U b) {
return a.compareTo(b);
}
...但是這也不起作用,因為Comparable<U>
不一定extend U
問題是您的鍵返回Comparable<V>
,但是您想比較其中的兩個。 那是不可能的。 可將Comparable<V>
與V
進行比較,但不能與另一個Comparable<V>
。
通常,這里有太多問題無法為您提供簡單的解決方案。 您需要完全重新考慮類型。 舉例來說,如果你想在Key
的get方法返回相互比較的對象,那么它應該返回V
而不是Comparable<V>
我希望以上建議至少能為您指明正確的方向。
現在就聲明它們,可以使用私有捕獲幫助器:
static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
final int cmp = compareHelper(key[i], a, b);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}
private static <T, U extends Comparable<U>> int compareHelper(Key<T, U> k, T a, T b) {
U av = k.get(a), bv = k.get(b);
return av.compareTo(bv);
}
或者,您可以從Key
完全擺脫V
並只對sort
進行約束,這將在U
上進行參數化:
public interface Key<T, V> {
public V get(T t);
}
static <T, U extends Comparable<? super U>> void sort(List<T> data, final Key<T, U> key[], final int dir[]) {
Collections.sort(list, new Comparator<T>() {
public int compare(T a, T b) {
for (int i = 0; i < key.length; i++) {
U av = k.get(a), bv = k.get(b);
final int cmp = av.compareTo(bv);
if (cmp != 0) return cmp * dir[i];
}
return 0;
}
});
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.