2010-08-10 36 views
4

這是一個容器的實現,它可以與具有兼容密鑰的任何其他容器進行比較。我有一個奇怪的錯誤使用Java中的泛型,有什麼想法?Java通用捕獲和可比較

private static class Container 
    <Key extends Comparable<? super Key>, Value> 
    implements Comparable<Container<? super Key, ?>> 
    { 
     public Key key; 
     public Value value; 
     public Container(Key k, Value v) { 
      key = k; 
      value = v; 
     } 
     public int compareTo(Container<? super Key, ?> o) { 
      return key.compareTo(o.key); 
     } 
    } 
    ... 

這是錯誤:

compareTo(capture#98 of ? super Key) in 
    java.lang.Comparable<capture#98 of ? super Key> cannot be applied to 
    (java.lang.Comparable<? super capture#822 of ? super Key>) 
      return key.compareTo(o.key); 
        ^
    1 error 
+0

好吧,我想我理解它,問題是**?**不匹配相同的類型,但仍然不知道如何解決它我想要求每個容器cl屁股可以與任何其他具有兼容密鑰類型的容器相媲美。 – 2010-08-10 15:23:20

回答

0

這工作,但看起來像一個黑客:

private static class Container 
    <K extends Comparable<? super K>, Value> 
    implements Comparable<Container<? extends Comparable<? super K>, ?>> 
    { 
     public K key; 
     public Value value; 
     public Container(K k, Value v) { 
      key = k; 
      value = v; 
     } 
     public int compareTo(Container<? extends Comparable<? super K>, ?> o) { 
      return -o.key.compareTo(key); 
     } 
    } 

我肯定會喜歡寫key.compareTo(o.key),但我沒有設法寫出必要的通用約束... :(

1

你根本就沒有正確地實現接口。您將Container定義爲實施Comparable<Pair<? super Key, Value>。這意味着它必須聲明一個方法:

public int compareTo(Comparable<Pair<? super Key, Value> o) 

但現在它不,因爲它缺少通配符。

在更廣泛意義上的問題是你的通配符匹配。 ?的意思是「任何類型匹配這些界限」。重要的是,?的不同實例可以是不同的具體類型;這就是「捕獲」類型所指的。

,你必須要「對了」的說法,你應該給該參數的名稱,以便您可以強制執行的身份(例如介紹該方法的通用參數)問號任何時候。每當你使用一個?,你基本上說,「我一點也不所有具體類型這個參數是什麼照顧」,所以你不能執行依賴於(如賦值精確匹配參數的任何操作)。


編輯:從更具體的意義上說,我認爲你的意圖略有偏差。您已嘗試在特定的Key類型上聲明Container,以與Key的不同(超類)上的Container相比較。我不相信這是一個好主意,因爲它引入了一些不對稱。

例如,您正在嘗試使Container<String>Container<Object>進行比較。但反過來做比較甚至不會編譯。這種情況對你來說似乎有效嗎?我期望的可比性是對稱的,它會混淆我a.compareTo(b)是1,但b.compareTo(a)返回-1而是拒絕編譯。這就是爲什麼,例如Double執行Comparable<Double>而不是Comparable<? super Double>

編輯 for plain answer:所以你應該擺脫那些通配符,因爲它不可能與任意對象進行比較。這樣的定義將如下所示:

private static class Container 
<Key extends Comparable<Key>, Value> 
implements Comparable<Container<Key, ?>> 
{ 
    ... 

    public int compareTo(Container<Key, ?> o) { 
     return key.compareTo(o.key); 
    } 
} 
+0

我怎麼給參數一個名字? – 2010-08-10 15:26:15

+0

'private static class MyStructure ,Value>'定義新的參數類型'T'。 – 2010-08-10 15:29:51

+0

聲明一種類似'private 方法(Comparable >)'的方法。這將接受任何可比較的<對<?超級鍵,值>>會匹配,但現在你有'T'標籤可以在整個方法中使用。多個對'T'的引用指的是相同的類型,而對多個引用''的引用通常指不同的類型。 – 2010-08-10 15:31:24

-3

出於某種原因,Eclipse的插入,當你創建一個Comparable型但這沒有任何意義的「超級類型?」(這類型的超將在compareTo()工作?) 。

剛剛擺脫「?超級」的,它會編譯。

5

佩奇:生產者延伸,消費類超。

讓我們從compareTo方法向後工作。你想比較一個容器,並且你想用鍵比較(因此是關鍵。的compareTo(o.key))。這意味着您的o必須產生Key,並且您的key必須消耗Key。第一部分表示您的方法聲明應該是public int compareTo(Container<? extends Key, ?> o),這意味着您應該執行Comparable<Container<? extends Key, ?>>。第二部分意味着你的Key應該是Comparable<? super Key>,這是你的方式。

private static class Container<Key extends Comparable<? super Key>, Value> 
        implements Comparable<Container<? extends Key, ?>> { 

    public Key key; 
    public Value value; 

    public Container(Key k, Value v) { 
     key = k; 
     value = v; 
    } 

    public int compareTo(Container<? extends Key, ?> o) { 
     return key.compareTo(o.key); 
    } 
} 

編輯: 繼正好下面的意見,聲明將是如下。請注意,按鍵中的flip將調用compareTo,並且Key不再需要實現Comparable。你只需要採取Container可以產生一些關鍵的,可以消耗Key

private static class Container<Key, Value> implements 
     Comparable<Container<? extends Comparable<? super Key>, ?>> { 

    //fields and constructors... 

    public int compareTo(Container<? extends Comparable<? super Key>, ?> o) { 
     return -o.key.compareTo(key); 
    } 
} 
+0

我不完全同意這一點,但也許我沒有理解它。我看到它的方式,您的'容器'與其他容器相比,它具有從第一個密鑰導出的密鑰。我希望Contaner能夠與任何其他容器相比,它具有與第一個密鑰相同的密鑰。 – 2010-08-12 10:52:42

+0

@Helltone:鑑於你希望其他人的鑰匙可以與第一個鑰匙相媲美,第一個鑰匙的鑰匙實際上並不需要可比(儘管它可能會是)。編輯上面的答案。 – ILMTitan 2010-08-12 19:14:37

+0

這是我在發佈的答案中所做的,但我實際上並不滿意** - o。**'key.compareTo' – 2010-08-13 09:21:04