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

che*_*eng 4 java generics comparable comparator

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

public class Pair<T1 extends Comparable, T2 extends Comparable>
Run Code Online (Sandbox Code Playgroud)

但是JDK 1.6编译器会生成关于此的警告:

Comparable is a raw type. References to generic type Comparable<T> should be parameterized
Run Code Online (Sandbox Code Playgroud)

然后我尝试添加类型参数,代码现在看起来像这样:

public class Pair<T1 extends Comparable<? extends Object>,
                  T2 extends Comparable<? extends Object>>
Run Code Online (Sandbox Code Playgroud)

现在一切顺利,直到我尝试为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;
        }
    };
Run Code Online (Sandbox Code Playgroud)

该代码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)
Run Code Online (Sandbox Code Playgroud)

任何人都知道这个错误消息是什么意思?
欢迎任何有关此主题的提示.

更新:
这是完整的代码:

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;
        }
    };
}
Run Code Online (Sandbox Code Playgroud)

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

Vin*_*rat 9

我会这样宣布我的课程:

public class Pair<T1 extends Comparable<T1>, T2 extends Comparable<T2>> 
Run Code Online (Sandbox Code Playgroud)

意味着对象与它们所属的对象相当(您的错误意味着编译器无法确保将对象与同类型的其他对象进行比较).


我的编辑代码正确编译:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,您应该为比较器创建一个单独的类(或静态最终类),以便更直观地使用它,并且不会增加每个Pair实例的权重.


Dam*_*ash 8

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

public interface Comparable<T> { 

   public int compareTo(T o);

} 
Run Code Online (Sandbox Code Playgroud)

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

pubilc class ICanComparteWithMyself implements Comparable<ICanComparteWithMyself> { 

public int compareTo(ICanComparteWithMyselfo)    
   //code for compration
} 
Run Code Online (Sandbox Code Playgroud)

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

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

   public int compareTo(T o)    
       //code for compration
    } 
}
Run Code Online (Sandbox Code Playgroud)

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

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

}
Run Code Online (Sandbox Code Playgroud)

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

 public class ICanCompareStrings implements Comparable<String> {
      public int compareTo(String o)    
           //code for compration
      }
 }
Run Code Online (Sandbox Code Playgroud)

因此对于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类,每个参数都可以与从它们传递的类进行比较.

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