簡體   English   中英

區別“ <T extends Comparable<T> &gt;“和” <T extends Comparable<Comparable<T> &gt;&gt;”?

[英]Difference between “<T extends Comparable<T>>” and “<T extends Comparable<Comparable<T>>>”?

在表達式<T extends Comparable<T>>中的簽名就像

public static <T extends Comparable<T>> foo(T x) { ... }

T的描述依賴於Comparable<T>

如果T擴展了Comparable<T> ,並且Comparable<T>擴展了Comparable<Comparable<T>> ,那么它是否會延伸T擴展Comparable<Comparable<T>>

IOW, extends關系是否可傳遞?

如果是這樣,為什么不呢

public static <T extends Comparable<Comparable<T>>> int compare(T x, T y) {
    return x.compareTo(y);
}

相當於

public static <T extends Comparable<T>> int compare(T x, T y) {
    return x.compareTo(y);
}

事實上,最后一個定義編譯,而上面的定義無法編譯,錯誤

comp.java:7: compareTo(java.lang.Comparable<T>) in 
java.lang.Comparable<java.lang.Comparable<T>> cannot be applied to (T)
            return x.compareTo(y);

謝謝!

我想你在這里做了一個不正確的邏輯跳躍。

T extends Comparable<T>

並不意味着

Comparable<T> extends Comparable<Comparable<T>>

簡短的比喻

假設一個岩石破碎機是任何可以壓碎岩石的材料, 岩石恰好能夠破碎自己。 所以搖滾是一種搖滾破碎機。 這是否意味着岩石可以粉碎任何可以粉碎岩石的物質? 顯然不是: 鋼鐵也可能是碎石機,而岩石可能不會壓碎鋼鐵。


長(基於代碼)類比

假設我有一個Additive<T>接口,可用於描述您可以對T對象執行add操作並返回T任何類型。

現在讓我們說我有一些方法的簽名如下:

public static <T extends Additive<T>> add(T x, T y) { ... }

由於x必須是我可以添加T的類型,因此可以按如下方式實現此方法:

return x.add(y);

說得通? 好,很好; 但現在讓我們假設你在你的問題中做出的假設: Additive<T>必須擴展Additive<Additive<T>> ; 如果是這種情況,那么我可以假設我可以向x添加任何實現 Additive<T> 類型的實例。

這是假設失敗的地方。 我可能有類型,說...

// A 32-bit integral number supporting addition
public class Int32 implements Additive<Int32> { ... }

這有道理,對嗎? 我也可以這樣:

// A list of 32-bit integral numbers supporting appending
public class Int32List implements Additive<Int32> { ... }

現在,如果T extends Additive<T>暗示Additive<T> extends Additive<Additive<T>>那么我應該能夠這樣做:

Additive<Int32> x = new Int32(5);
Additive<Int32> y = x.add(new Int32List());

這有任何意義嗎?

沒什么特別的

<T extends Comparable<T>>

考慮

public class Foo implements Comparable<Foo>{
     int compareTo(Foo x);
}

我甚至不認為我們可以說它是遞歸定義的,它只是自我引用。

Comparable<T> extends Comparable<Comparable<T>>

也許我誤解了你傳達的關系,但這種說法是不真實的。 Comparable<T>不會擴展任何內容。

要記住的基本問題是Java泛型由編譯單元和編譯時限限定。 這只是語法糖! (多少次我忘記了這一點並最終推斷出你的方式, 就像 Java Generics 在運行時實際上暗示了泛型類型系統一樣 。)

規格

The scope of a class' type parameter is the entire declaration of the class 
including the type parameter section itself. 

Therefore, type parameters can appear as parts of their own bounds, or as 
bounds of other type parameters declared in the same section.

沒有遞歸,也沒有定義新類型。

以機智:

package so_6949760;

import java.util.HashMap;

public class SweetCompilingGenerics {

    @SuppressWarnings("serial")
    public static class Sweet<X> extends HashMap<X, Sweet<X>> {}

    public static void main(String[] args) {
        Sweet<String> sweetStr = new Sweet<String>();
        Sweet<Sweet<Integer>> whatever = new Sweet<SweetCompilingGenerics.Sweet<Integer>>();

        assert sweetStr.getClass().equals(whatever.getClass()) : "who made generics a runtime mechanism?";
        assert sweetStr.getClass() == whatever.getClass() : "who made generics a runtime mechanism?";

        System.out.format("Is %s a Sweet<String> ?\n", sweetStr.getClass().getCanonicalName());
        System.out.format("Is %s a Sweet<Sweet<Integer>> ?\n", whatever.getClass().getCanonicalName());
    }
}

將輸出甜蜜的秘密:

Is so_6949760.SweetCompilingGenerics.Sweet a Sweet<String> ? 
Is so_6949760.SweetCompilingGenerics.Sweet a Sweet<Sweet<Integer>> ?

我是否可以如此向一位極客提供建議? 始終閱讀規范

[post accept edit]:剛剛發現IBM的這篇內容豐富的文章 這幾乎解決了OP的所有問題。 (推薦的)。

Comparable<T>不會擴展Comparable<Comparable<T>> (僅因為T擴展Comparable<T> ),就像List<String>不擴展List<Object> (因為String擴展了Object )。

請參閱Oracle的此文檔以閱讀有關泛型和繼承的更多信息。

暫無
暫無

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

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