簡體   English   中英

Java通用方法無法調用約束更寬松的另一個通用方法並返回其值

[英]Java generic method cannot call another generic method with looser constraint and return its value

我想這樣做:

<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<? super T>而不是Comparable<T>

正如Johannes Kuhn在其評論中指出的那樣, Date的子類將隱式實現Comparable<Date>而不是Comparable<DateSubclass> ,因此需要Comparable<? super T> Comparable<? super T>

有關更多信息,請參見: 什么是PECS(生產者擴展了超級消費者)?

問題在於,可以使用以下類來調用第一個方法:

class MyDate extends Date {}

然后,第一種方法中的T推斷為MyDate ,但第二種方法中的T不能為MyDate ,因為MyDate不擴展Comparable<MyDate> -它僅擴展Comparable<Date> ...

因此,編譯錯誤的根本原因是Java泛型是不變的。 這就是為什么Kotlin(其泛型支持聲明站點差異)接受代碼而沒有問題的原因。

要在Java中解決此問題,可以使用通配符類型,如Jacoc G.的答案所示。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM