Java Generics:compareTo和“capture#1-of?”

时间:2009-11-20 14:57:32

标签: java generics comparable

以下是一条错误消息:

public static List<Comparable<?>> merge(Set<List<Comparable<?>>> lists) {
    List<Comparable<?>> result = new LinkedList<Comparable<?>>();
    HashBiMap<List<Comparable<?>>, Integer> location = HashBiMap.create();

    int totalSize;
    for (List<Comparable<?>> l : lists) {
        location.put(l, 0);
        totalSize += l.size();
    }

    boolean first;
    List<Comparable<?>> lowest; //the list with the lowest item to add
    int index;

    while (result.size() < totalSize) {
        first = true;

        for (List<Comparable<?>> l : lists) {
            if (! l.isEmpty()) {
                if (first) {
                    lowest = l;
                }
                else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) { //error here
                    lowest = l;
                }
            }
        }
        index = location.get(lowest);
        result.add(lowest.get(index));
        lowest.remove(index);
    }
    return result;
}

错误是:

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

这里发生了什么?我创建了所有Comparable的类型,因此我可以调用.compareTo并对此列表进行排序。我是否错误地使用了泛型?

1 个答案:

答案 0 :(得分:22)

List<?>表示“任何内容列表”,因此具有此类型的两个对象不同:一个可以是String的列表,另一个可以是BigDecimal的列表。显然,那些不一样。

List<T>表示“除了T再次看到T之外的任何内容列表”。

当你在不同的地方使用相同的类型时,你必须告诉编译器。尝试:

public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
    List<T> result = new LinkedList<T>();
    HashBiMap<List<T>, Integer> location = HashBiMap.create();

[编辑]那么<T extends Comparable<? super T>> List<T>是什么意思?第一部分定义了具有以下属性的类型T:它必须实现接口Comparable<? super T>(或Comparable<X>,其中X也是根据T定义的)。

? super T表示Comparable支持的类型必须为T或其中一种超类型。

想象一下这个继承:Double extends Integer extends Number。这在Java中是不正确的,但想象Double只是Integer加上一小部分。在这种情况下,适用于Comparable的{​​{1}}也适用于NumberInteger,因为它们都来自Double。因此,Number会满足Comparable<Number> super TNumberInteger的{​​{1}}部分。

只要这些类型中的每一个都支持Double接口,它们也满足声明的第一部分。这意味着,您可以为Comparable传递Number,当列表中有TInteger个实例时,生成的代码也会生效。如果DoubleInteger,您仍然可以使用T,但Double不可能,因为它不再满足NumberT extends Comparable但是,部分仍然可以工作。

下一步是要了解superstatic之间的表达式只是声明了代码中稍后使用的List类型的属性。这样,您就不必一遍又一遍地重复这个长的声明。它是方法行为的一部分(如T),而不是实际代码的一部分。