4

我想编写一个通用的 Pair 类,它有两个成员:键和值。该类的唯一要求是键和值都应实现 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 生成一个比较器。(以下代码在 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()

4

3 回答 3

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

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

于 2012-10-23T08:22:00.720 回答
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作为泛型参数的类,我们可以使用 classpublic MyGenericCanCompareToItself而不是ICanCompareStrings.

编辑:

因此,当我们现在介绍了基础知识时,我们可以去解决您的问题

您的课程描述如下所示

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

这没有太多感觉,因为更不一样<?>

这个描述说:

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

使用此代码,在泛型参数不知道之前您无法继续前进,然后在那里进行操作,最终得到类似的结果。

first.getKey.compareTo(null);

这就是为什么您在尝试强制转换时代码不编译的原因,预期类型为空。


要改变这一点,您需要确定您的泛型参数应该具有可比性。

例如可以在 selft 上进行比较

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 类,每个参数都可以与从它们提供的类进行比较。

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

于 2012-10-23T08:37:27.273 回答
-1

如果您知道以下之间的区别:

List<Object>

List<String>

......这会更容易。基本上,它们是 java 中的两种不同类型(不是您想象的“相同”列表类型)。

通用类型“逻辑”并不像您在脑海中想象的那样简单直接。

我认为你应该将你的“Pair”类声明如下:

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

既然您已经使“T1”T2”具有可比性,为什么还要实现比较器?

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

无论哪种方式,代码中都存在冗余。

于 2012-10-23T09:06:20.240 回答