2015-06-09 66 views
0

我写了一个小型列表分类器,它使用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的警告有关这条线在分拣机:

报告警告说,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); 
} 

回答

2

你需要使用一个类型参数的说,两个“未知”类型是相同的。我想,也许你应该你的方法签名更改从:

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>,但你想比较其中两个;这是不可能的。 A Comparable<V>可以与V比较,但不能与另一个Comparable<V>比较。

一般来说,这里有太多的问题给你一个简单的解决方案。你需要完全重新考虑类型。例如,如果您希望Key的get方法返回可与相媲美的对象,则应该返回V而不是Comparable<V>

我希望上面的建议至少能指引您朝着正确的方向发展。

+0

我已经改变了Key.get'的'定义返回'V'而非可比'',按照你的建议,但我仍然不知道我怎么能告诉(典型值)对于任何给定的循环迭代,e系统“av”和“bv”共享相同的类型。 –

+0

@StuartCaie你应该可以通过引入一个类型变量来完成这一点,就像我的答案的顶部。例如,将内部循环中的三行移动到一个新方法中,该方法通过键返回的类型进行参数化;类似于:'> int compareParts(Key key,T a,T b)' – davmac

0

你现在他们的权利声明,你可以使用一个私人拍摄辅助方式:

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; 
     } 
    }); 
} 
相关问题