我写了一个小型列表分类器,它使用Key
对象从可比较形式的对象中提取特定“键”。然后,分拣机依次按照所有的键对列表进行分类。如何告诉Java两个通配符类型相同?
分拣机可以使用排序任何在给定类型的对象上工作的键。每个键都可以处理一种类型的对象,并始终返回相同类型的可比值。
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的警告有关这条线在分拣机:
报告警告说,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);
}
我已经改变了Key.get'的'定义返回'V'而非可比'',按照你的建议,但我仍然不知道我怎么能告诉(典型值)对于任何给定的循环迭代,e系统“av”和“bv”共享相同的类型。 –
@StuartCaie你应该可以通过引入一个类型变量来完成这一点,就像我的答案的顶部。例如,将内部循环中的三行移动到一个新方法中,该方法通过键返回的类型进行参数化;类似于:'> int compareParts(Key key,T a,T b)' –
davmac