Java中的可比较和比较器接口

时间:2012-10-23 08:20:59

标签: java generics comparator comparable

我想写一个通用的Pair类,它有两个成员:key和value。这个类的唯一要求是key和value都应该实现Comparable接口,否则Pair类不会接受它们作为类型参数。
首先,我这样编码:

public class Pair<T1 extends Comparable, T2 extends Comparable>

但是JDK 1.6编译器会产生警告:

Comparable is a raw type. References to generic type Comparable<T> should be parameterized

然后我尝试添加类型参数,现在代码如下:

public class Pair<T1 extends Comparable<? extends Object>,
                  T2 extends Comparable<? extends Object>>

现在一切顺利,直到我尝试为Pair生成Comparator。(以下代码在Pair类中)

public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            *first.getKey().compareTo(second.getKey());*
            return 0;
        }
    };

代码first.getKey().compareTo(second.getKey());会产生错误说明:

The method compareTo(capture#1-of ? extends Object) in the type Comparable<capture#1-of ? extends Object> is not applicable for the  arguments (T1)

任何人都知道此错误消息的含义是什么?
欢迎任何有关此主题的提示。

更新
这是完整的代码:

public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>> {
    private T1 key;
    private T2 value;

    public static int ascending = 1;
    public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            int cmp = first.getKey().compareTo((T1)(second.getKey()));
            if (cmp > 0)  return ascending;
            return -ascending;
        }
    };
}

@MarvinLabs你能解释一下为什么编译器无法确保将对象与同类型的其他对象进行比较的原因。在上面的代码中,second.getKey()返回T1类型,其类型与first.getKey()

相同

3 个答案:

答案 0 :(得分:9)

我会这样宣布我的课程:

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> 

意味着对象与它们相同类型的对象具有可比性(您的错误意味着编译器无法确保将对象与同类型的其他对象进行比较)。


我的编辑代码正确编译:

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> {
    private T1 key;
    private T2 value;

    public T1 getKey() {
        return key;
    }

    public T2 getValue() {
        return value;
    }

    public final Comparator<Pair<T1, T2>> KEY_COMPARATOR = new Comparator<Pair<T1, T2>>() {
        public int compare(Pair<T1, T2> first, Pair<T1, T2> second) {
            return first.getKey().compareTo(second.getKey());
        }
    };

    public static void test() {
        Pair<String, Integer> p1 = new Pair<String, Integer>();
        Pair<String, Integer> p2 = new Pair<String, Integer>();

        p1.KEY_COMPARATOR.compare(p1, p2);
    }
}

然而,您应该为比较器创建一个单独的类(或静态最终类),以便更直观地使用&amp;也不会增加每个Pair实例的权重。

答案 1 :(得分:8)

让我们先看一下界面设计。

public interface Comparable<T> { 

   public int compareTo(T o);

} 

我们必须说这是很典型的。因此,如果我们的课程需要实现它,我们就这样做。

pubilc class ICanComparteWithMyself implements Comparable<ICanComparteWithMyself> { 

public int compareTo(ICanComparteWithMyselfo)    
   //code for compration
} 

当我们看到通用参数类型时,确定我们将要操作的内容,因此对于泛型我们以相同的方式行事

public class ICanCompareMyGeneric<T> implements Comparable<T> {

   public int compareTo(T o)    
       //code for compration
    } 
}

在你的情况下,我们希望它确保泛型参数实现是自己的Comparable,为此我们需要这样做

public class MyGenericCanCompareToItself<T extends Comparable<T>> { 

}

我们可以看到,这种情况很常见。预期(或不是)的限制是我们可以处理为其自身类型实现Comparable的类。如果我们有

 public class ICanCompareStrings implements Comparable<String> {
      public int compareTo(String o)    
           //code for compration
      }
 }

因此,对于作为通用参数的类MyGenericCanCompareToItself,我们可以使用类public MyGenericCanCompareToItself,但不能使用ICanCompareStrings

修改

所以,当我们介绍基础知识时,我们可以去解决你的问题

您的课程描述如下所示

public class Pair<T1 extends Comparable<? extends Object>, T2 extends Comparable<? extends Object>>

这没有多少感觉,因为它与<?>

相同

此描述说:

  

我是一个Pair类,它使用两个通用参数,可以使用我不知道的东西进行比较。

使用这段代码,你不能在通用参数不知道之前进展,然后在那里操作,最终得到这样的东西。

first.getKey.compareTo(null);

这就是为什么你编写的代码在你尝试强制转换时不能编译,期望的类型为null。


要更改您需要确定您的通用参数应具有可比性的类型。

例如,可以在itselft上进行比较

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>

这条描述说:

  

我是一个使用两个参数的Pair类,每个参数都可以与自身进行比较。

这就是你可能正在寻找的东西,另外它们可以在一些可以超级T1或T2的东西上进行比较

public class Pair<T1 extends Comparable<? super T1>, T2 extends Comparable<? super T2>>

此描述说:

  

我是一个使用两个参数的Pair类,每个参数都可以与从它们传递的类进行比较。

我希望这可以帮助你使用泛型; - )。

答案 2 :(得分:-1)

如果你知道:

之间的区别
List<Object>

List<String>

......会更容易。基本上,它们是java中的两种不同类型(不是你认为的“相同”List类型)。

通用类型“逻辑”并不像你在脑海中想象的那样直截了当。

我认为您应该将您的“配对”类声明如下:

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>>

因为你已经使“T1”T2“具有可比性,你为什么要实现比较器?

如果你想使用“Collections.sort(myCollection,myComparator)”,那么你不必声明“T1”和“T2”是“可比的”......只要确保你的“KEY_COMPARATOR”接受他们......

无论哪种方式,代码都有冗余。