具有通用参数的 compareTo 发出警告

compareTo with generic arguments is giving warning

我想比较 less 方法中的两个 Comparable 类型的参数。但是,如果我使用 comapreTo,它会在类型转换时出现错误:

private boolean less(Comparable<T> u, Comparable<T> v) {
    return u.compareTo(v) < 0;
}

我通过类型转换传递给 compareTo 的参数解决了这个问题。但它仍然给我警告(类型安全:从 Comparable 到 T 的未经检查的转换)。为什么会这样。难道我做错了什么。实现此目标的最佳方法是什么。

private boolean less(Comparable<T> u, Comparable<T> v) {
    return u.compareTo((T) v) < 0;
}

最初的错误是正确的,警告是正确的:你的技巧非常不安全:你不能将 v 转换为 T。

因为您的方法有两个参数 u 和 v,每个参数都是 class 的一个实例,它实现了 compareTo(T 的某个实例)。

准确地说:u可以比T,v可以比T。

但是,在内部,你想比较u和v。绝对没有保证你可以做到。

例如,这是正确的:

private static <X> boolean less(Comparable<X> u, X v)
    {
    return u.compareTo(v) < 0;
    }

由于 u 的类型为 Comparable<T>u.compareTo() 采用 T。您正在传递它 v,一个 Comparable<T>,这是不兼容的。

您可能会在脑海中假设实现 Comparable 的类型与其自身具有可比性。但是在技术层面上没有这样的要求。我创建类型 Foo 是完全合法的,即 Comparable<Bar>,即它与 Bar 相比,其中 FooBar 是完全不相关的。尝试将 Foo 传递给 Foo 对象的 compareTo 会崩溃。

如果你想限制两个参数的类型相同且与自身相比较,你可以这样做

private <T extends Comparable<? super T>> boolean less(T u, T v) {
    return u.compareTo(v) < 0;
}

但是,就此函数而言,两个参数类型相同的约束在技术上不是必需的(尽管在所有正常用例中都应该如此)。在泛型中,我们总是希望使用尽可能少的限制,正如其他答案所提到的那样,

private <T> boolean less(Comparable<T> u, T v) {
    return u.compareTo(v) < 0;
}

在您的评论中,您提到您正在比较 Comparable<T>[] 中的元素。那不是一种允许您比较元素的数组类型。你只知道它是一个元素数组,与某个 T 可比,但与自身不可比。更有用的是 T[],其中 T 有一个界限,它可以与自身相媲美:

class Whatever<T extends Comparable<? super T>> {
    //...
    T[] yourArray;
}