簡體   English   中英

如何告訴Java兩個通配符類型相同?

[英]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);

它警告avbv聲明為原始類型: Comparable而不是Comparable<?> 他們是。 但是,如果我將類型更改為Comparable<?> ,則下一行av.compareTo(bv)失敗,因為兩個不同的Comparable<?>不一定是同一類型。 在我的特定實現中,它們是,但是我不知道如何將其表達給類型系統。

如何告訴類型系統avbv具有完全相同的類型? 我無法通過提供特定類型(例如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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM