我想这样做:

<T extends java.util.Date> T a(@Nonnull T... dates) {
    return b(dates);  // compile error
}

<T extends Comparable<T>> T b(T... comparables) {
   return comparables[0];
}

但是除非我在a中插入强制类型转换,否则它无法编译:
<T extends java.util.Date> T a(@Nonnull T... dates) {
    return (T) b(dates);  // warning about unsafe cast in IntelliJ
}

<T extends Comparable<T>> T b(T... comparables) {
   return comparables[0];
}

有趣的是,如果我从a中删除了泛型,它将起作用:
java.util.Date a(java.util.Date... dates) {
    return b(dates);
}

<T extends Comparable<T>> T b(T... comparables) {
   return comparables[0];
}

而且,如果我将原始代码移植到Kotlin,它也可以工作(这使我认为这是Java的限制,而不是根本上不可知的东西):
fun <T: java.util.Date> a(dates: Array<T>): T {
    return b(dates);
}

fun <T: Comparable<T>> b(comparables: Array<T>): T {
    return comparables[0];
}

我的问题是:Java的类型系统有什么特殊之处可阻止此类型的编译?在我看来,Java编译器可以只在后台插入强制类型转换(据我了解,这就是在其他情况下实现泛型的方式)。

最佳答案

无需强制转换即可将其编译。相反,当指定T必须扩展Comparable<T>时,可以使用有界通配符:

<T extends java.util.Date> T a(T... dates) {
    return b(dates);  // compiles fine
}

<T extends Comparable<? super T>> T b(T... comparables) {
    return comparables[0];
}

注意Comparable<? super T>而不是Comparable<T>

正如Johannes Kuhn在其comment中指出的那样,Date的子类将隐式实现Comparable<Date>而不是Comparable<DateSubclass>,因此需要Comparable<? super T>

有关更多信息,请参见:What is PECS (Producer Extends Consumer Super)?

07-24 09:49
查看更多