Java中的泛型 - 为什么我不被允许做可比较<! - ?扩展T - >而不是Comparable <! - ?超级T - >?

时间:2017-12-06 11:40:53

标签: java generics

我根据Jon Skeet的回答重写了这个ArrayIndexComparator类,以便它可以支持泛型类型:Get the indices of an array after sorting?

public class ArrayIndexComparator<T extends Comparable<? super T>> implements Comparator<Integer> {
    private final T[] array;

    public ArrayIndexComparator(T[] array) {
        this.array = array;
    }

    public Integer[] createIndexArray() {
        Integer[] indexes = new Integer[array.length];
        for (int i = 0; i < array.length; i++) {
            indexes[i] = i; // Autoboxing
        }
        return indexes;
    }

    @Override
    public int compare(Integer index1, Integer index2) {
        // Autounbox from Integer to int to use as array indexes
        return array[index2].compareTo(array[index1]);
    }
}

只要T类型或T的超类型实现Comparable接口(Comparable<? super T>),我就可以使用此类。

如果我写Comparable<? extends T>而不是Comparable<? super T>,编译器会给我一个错误:

@Override
public int compare(Integer index1, Integer index2) {
    // Autounbox from Integer to int to use as array indexes
    return array[index2].compareTo(array[index1]); // ERROR -> compareTo (capture<? extends T>) in Comparable cannot be applied to (T)
}

这个compareTo (capture<? extends T>) in Comparable cannot be applied to (T)错误是什么意思?

我可以假设定义一个实现AClass的类Comparable<AChildClassOfAClass>是没有意义的,但它是可能的:

class AClass implements Comparable<AChildClassOfAClass> {


    @Override
    public int compareTo(AChildClassOfAClass o) {
        return 0;
    }
}

class AChildClassOfAClass extends AClass {
}

在这个奇怪的场景中,如果我将其定义为ArrayIndexComparator,我假设能够使用ArrayIndexComparator<T extends Comparable<? extends T>>,因为在这种情况下TAClass,它实现{ {1}}结果是Comparable<AChildClassOfAClass>的子类(因此AClassComparable<? extends T>)。

当然,使用Comparable<AChildClassOfAClass extends AClass>更有意义,但我想如果我愿意,我应该能够做到。

为什么Java不允许我这样做?

非常感谢你的关注。

编辑:在阅读问题Difference between <? super T> and <? extends T> in Java的答案后,这是我理解的内容,我希望我理解正确:

Comparable<? super T>属于T类型,但array[index1]期望类型compareTo,即未知的特定类型的<? extends T>(或T本身,但是编译器无法保证)。

因此,编译器无法安全地将T转换为特定的未知类型,而如果我们使用T则可以执行此操作,因为在这种情况下<? super T>会预期未知作为参数的compareTo的超类型,并且当我们传递T时,编译器可以安全地将类型T强制转换为其超类型,因为类型T也是T 1}}(就像我们说supertype of T也是Integer,但Number不一定是Number

在这个Integer的情况下,我们尝试将Comparable<? extends T>传递给array[index1]方法,但编译器无法安全地转换类型compareToT所需的特定类型,这是未知的。

这就是我收到错误的原因。

这个想法是对的吗?

2 个答案:

答案 0 :(得分:1)

这种错误通常意味着您正在尝试编码一个没有意义的约束。在你的情况下,我们已经知道有些事情没有意义:

  

在这种情况下TAClass,它实现了Comparable<AChildClassOfAClass>

这个是真正的问题。您的课程允许您base.compareTo(child),但不能child.compareTo(base)。你已经调整了通用参数来处理这个问题,但是你只是把问题推到别处(幸运的是编译器很聪明地发现它!)。

错误实际上是什么

compareTo需要? extends T。即一些扩展T特定但未知的类型。编译器抱怨是因为我们试图传入T - 一般而言,它与未知类型不同(也不可分配)。我们唯一可以传递给这种方法的是null

进一步阅读

答案 1 :(得分:-1)

要管理?泛型类型参数,编译器使用&#34; capture&#34 ;;在您的情况下,capture-of-? super T

通用术语? super T表示&#34; T&#34;的任何超类;所以请注意它可以是Object;因此调用该方法时可能会有Comparable<Object>。但是,这是无效的:

Comparable<AChildClassOfAClass> yourComparable == new YourClass();
yourComparable.compareTo(new Object());

这是您的代码可能会使用该定义的内容。