如何告诉Java两个通配符类型是相同的? [英] How to tell Java that two wildcard types are the same?

查看:149
本文介绍了如何告诉Java两个通配符类型是相同的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我编写了一个小型列表分类器,它通过使用 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 final比较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;
}
});






$ b

例如,你可以有一个<$提取一个字符串(它是 Comparable )的c $ c> JSONStringKey 可以有一个单独的 JSONNumericKey 来提取一个 Double )(它也是 Comparable )。来自两个不同键的值将永远不会进行比较,但可以比较两个不同对象中的同一个键

  class JSONStringKey extends Sorter.Key< JSONObject,String> {
最终的字符串键;
JSONStringKey(String key){this.key = key;}
public String get(JSONObject o){return o.optString(key);}
}

class JSONNumericKey extends Sorter.Key< JSONObject,Double> {
最终的字符串键;
JSONNumericKey(String key){this.key = key;}
public Double get(JSONObject o){return o.optDouble(key);}
}

...

//按价格降序排序然后按名称升序
final Key< JSONObject,?> keys [] = {new JSONNumericKey(price),new JSONStringKey(name)};
sort(list,keys,new int [] { - 1,1});

Java在分拣机中对此行警告:

  final可比较的av = key [i] .get(a),bv = key [i] .get(b); 

它警告 av 和<$ c以原始类型声明$ c> bv :可比较而不是可比较<?> 。他们是。但如果我将类型更改为 Comparable<?> ,则下一行 av.compareTo(bv)失败,因为两个不同的 Comparable<?> 不一定是相同的类型。在我的具体实现中,他们,但我不知道如何向类型系统表达。



我怎么知道类型系统 av bv 具有完全相同的类型?我不能通过给定特定类型(例如 Comparable< String> )来修复它,因为在我的示例中,循环中的第一个键返回 String (它实现 Comparable< String> ),并且循环中的第二个键返回 Double (它实现了 Comparable< Double> )。

我可以写 @SuppressWarnings (rawtypes)上的键[i] .get()行和 @SuppressWarnings(unchecked) 在 av.compareTo(bv)行中,但我希望尽可能检查类型。



编辑:感谢davmac提供的答案,创建一个中间方法来修复特定的可比较类型:

  public int compare(T a,T b){
for(int i = 0; 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);
返回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 [])

然而,我不认为这可以用你的完整例子,因为从键的元素是不是是相同的类型:

  //按价格降序排序然后按名称升序排序
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 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];
}
返回0;
}

private< U extends Comparable< U>> int doCompareTo(U a,U b){
return a.compareTo(b);
}

...但这也行不通,因为 Comparable< U> 不一定扩展U 。问题在于你的Keys返回 Comparable< V> ,但你想比较其中的两个;这是不可能的。 Comparable< V> 可以与 V 进行比较,但不能与另一个比较< V>



一般来说,这里有太多的问题可以给你一个简单的解决方案。你需要完全重新考虑类型。例如,如果你希望 Key 的get方法返回可与彼此比较的对象,那么它应该返回 V 而不是可比较< V>



我希望以上建议至少指出你在正确的方向。


I have written a small list sorter that works by using Key objects to extract specific "keys" from objects in comparable form. The sorter then sorts the list in accordance with all the keys in turn.

The sorter can sort using any set of keys that work on the given types of object. Each key is able to deal with one type of object and always returns the same type of comparable value.

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;
            }
        });
    }
}

So, for example, you could have a JSONStringKey that extracts a String (which is Comparable), and you could have a separate JSONNumericKey that extracts a Double) (which is also Comparable). Values from two different keys will never be compared, but the same key across two different objects will be compared.

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 warns about this line in the sorter:

final Comparable av = key[i].get(a), bv = key[i].get(b);

It warns that av and bv are declared with raw types: Comparable instead of Comparable<?>. And they are. But if I change the type to Comparable<?>, then the next line, av.compareTo(bv) fails, because two different Comparable<?> are not necessarily the same type. In my specific implementation, they will be, but I don't know how to express that to the type system.

How can I tell the type system that av and bv have exactly the same type? I can't "fix" it by giving a specific type (e.g. Comparable<String>) because in my example, the first key in the loop returns String (which implements Comparable<String>) and the second key in the loop returns Double (which implements Comparable<Double>).

I could write @SuppressWarnings("rawtypes") on the key[i].get() lines and @SuppressWarnings("unchecked") on the av.compareTo(bv) line, but I want to have the types checked as far as possible.

EDIT: thanks to the answer from davmac, creating an intermediary method that fixes to a specific comparable type works correctly:

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);
}

解决方案

You need to use a type parameter to say that two 'unknown' types are the same. I thought that maybe you should change your method signature from:

static <T> void sort(List<T> data, final Key<T, ?> key[], final int dir[]) 

to

static <T,U> void sort(List<T> data, final Key<T,U> key[], final int dir[])

However, I don't think this would work with your full example, because the elements from the keys are not the same type:

// sort by price descending then name ascending
final Key<JSONObject, ?> keys[] = { new JSONNumericKey("price"), new JSONStringKey("name") };
sort(list, keys, new int[]{-1, 1});

So, instead, you could extract the relevant part from the sorter into a generic method:

        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);
        }

... but this wouldn't work either, because a Comparable<U> doesn't necessarily extend U. The problem is that your Keys return Comparable<V>, but you want to compare two of these; that's not possible. A Comparable<V> can be compared with a V, but not with another Comparable<V>.

In general, there are too many issues here to give you a simple solution. You need to re-think the types completely. For instance, if you want the Key's get method to return objects that are comparable with each other, then it should return V and not Comparable<V>.

I hope the suggestions above at least point you in the right direction.

这篇关于如何告诉Java两个通配符类型是相同的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆