2010-08-28 201 views
62

我想要定義一個實現Comparable的抽象類。當我定義,定義如下類:Java抽象類使用泛型實現接口

public abstract class MyClass implements Comparable <MyClass> 

子類必須實現compareTo(MyClass object)。相反,我希望每個子類都實現compareTo(SubClass object),接受它自己類型的對象。當我嘗試用類似的方式定義抽象類時:

public abstract class MyClass implements Comparable <? extends MyClass> 

它抱怨說「超類型不能指定任何通配符」。

有沒有解決方案?

回答

40

這在我看來有點太冗長,但工作原理:

public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> { 

} 

public class SubClass extends MyClass<SubClass> { 

    @Override 
    public int compareTo(SubClass o) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

} 
+0

我認爲就是這樣。 – Pointy 2010-08-29 00:04:25

+2

考慮(1)class MyImpl1 extends MyClass {...};和(2)MyImpl2類擴展MyClass {public int compareTo(MyImpl1 o){...}}。 MyImpl2沒有做正確的事情。 – emory 2010-08-29 00:41:42

+1

如果我們假設每個子類都使用自己的類作爲泛型參數來擴展MyClass,那麼解決方案是正確的。但是,埃默裏指出,似乎沒有辦法確保這一點。 – Cem 2010-08-29 08:46:09

1

我不知道你需要捕獲:

首先,添加的compareTo抽象類...

public abstract class MyClass implements Comparable <MyClass> { 

@Override 
public int compareTo(MyClass c) { 
... 
}  
} 

然後添加實現...

public class MyClass1 extends MyClass { 
... 
} 

public class MyClass2 extends MyClass { 
... 
} 

呼叫比較會調用超類方法......

MyClass1 c1 = new MyClass1(); 
MyClass2 c2 = new MyClass2(); 

c1.compareTo(c2); 
+0

這不正是Cem描述他的問題的方式嗎?你將如何使用不同的參數類型在'MyClass1'或'MyClass2'中實現'compareTo'? – whiskeysierra 2010-08-29 00:13:52

+0

你是對的......用另一種方式閱讀問題。 – zevra0 2010-08-29 00:16:27

17

除了你遇到聲明簽名機械的困難,我們的目標沒有太大的意義。你正試圖建立一個協變比較函數,這個函數打破了建立派生類可以定製的接口的想法。

如果你定義一些子類​​使得它的情況下,只能相對於其他​​實例,則如何​​滿足MyClass定義的合同嗎?回想一下MyClass是說它和它的任何類型可以與其他MyClass實例進行比較。您正試圖使​​不正確,這意味着​​不符合MyClass的合同:由於​​的要求更嚴格,因此您不能用​​替代MyClass

這個問題主要集中在協方差和反變量上,以及它們如何通過類型派生來改變函數簽名。您可以放寬對參數類型的要求 - 接受比超類型的簽名要求更寬的類型 - 您可以加強對返回類型的要求 - 承諾返回比超類型簽名更窄的類型。這些自由中的每一個仍然允許超類型的派生類型的完美替換;當通過超類型的接口使用派生類型時,調用者無法區分差異,但具體使用派生類型的調用者可以利用這些自由。

Willi's answer教導一些關於泛型聲明的內容,但我希望你在接受技術之前重新考慮你的目標,而不要犧牲語義。

+0

我同意這個答案。另外,我們應該編寫接口而不是類。實際的實現類可能是匿名類,本地類(嵌套在方法中),私有(嵌套在類中)或者包私有,因此不在我們的範圍內。 – emory 2010-08-29 00:46:23

+2

我看到的另一個問題是將子類對象存儲在集合中。我應該可以用'List '而不是'List >'來存儲它們。當你得到這些對象之一併調用'equals(anObject)'時會調用什麼? – TheLQ 2010-08-29 00:59:27

+0

謝謝你的回答。實際上,我正在尋找一個合約,強制每個子類都有一個compareTo()方法,僅用於其自己的類,但不適用於其他任何子類。在這個意義上,我的製造的泛型定義可能會產生誤導。 – Cem 2010-08-29 08:31:15

3

看到Java的自己的例子:在SEH的評論

public abstract class Enum<E extends Enum<E>> implements Comparable<E> 
    public final int compareTo(E o) 

:通常的說法是正確的。但泛型使得類型關係更加複雜。子類可以不是MyClass在威利的溶液亞型....

SubClassAMyClass<SubClassA>一個亞型,但不是MyClass<SubClassB>

類型MyClass<X>的子類型定義了一個合同compareTo(X)其中所有其亞型的絕榮譽。那裏沒有問題。

+1

這是一個很好的例子,但它不同於傑姆的原始問題。現在,我可能從字面上看他的代碼;也許這正是他試圖寫的東西。在這種情況下,Enum接口的Comparable方面是關於一個特定的子類可以對*自身做些什麼(或者,而不是它本身的實例),而不是它能用Enum類派生的類型做什麼一般。如果這就是傑姆之後的事情,那麼我認爲你的回答比我的更合適。 – seh 2010-08-29 02:56:00

+0

我想只要所有的子類都是MyClass 的子類型就可以了。但我不確定是否會在未來的步驟中導致問題。這是我第一次用泛型進行設計。 – Cem 2010-08-29 08:34:07

+0

這是一個不好的例子。枚舉是一種特殊情況 - 枚舉類型由語言提供,並且具有特定的形式(enum A'將實現Enum '),這對於用戶定義的類來說並非如此。 – newacct 2012-11-30 10:42:37

1
public abstract class MyClass<T> implements Comparable<T> { 

} 

public class SubClass extends MyClass<SubClass> { 

    @Override 
    public int compareTo(SubClass o) { 
     // TODO Auto-generated method stub 
     return 0; 
    } 

} 
+0

這不會將類型參數T限制爲MyClass的子類。 – 2014-07-21 09:39:54

+0

@StevoSlavić:那麼?這是完全類型安全的。 – newacct 2014-07-21 19:03:47

+0

如果我正確理解原始問題/示例,其中一個想法是將T限制爲MyClass的子類,而編譯器不允許。 – 2014-07-21 21:25:41

0

我知道你說你想「的compareTo(子類對象),接受自己的類型的對象」,但我還是建議聲明抽象類是這樣的:

public abstract class MyClass implements Comparable <Object> 

,做一個instanceof檢查在MySubClass覆蓋的compareTo時:

@Override 
public int compareTo(Object o) { 
    if (o instanceof MySubClass)) { 
     ... 
    } 
    else throw new IllegalArgumentException(...) 
} 

類似 '等於' 或 '克隆'

1

發現了另一個解決方案:

  1. 定義在其上構成comaprable(例如ComparableFoo)的字段的接口
  2. 實現父類的接口
  3. 實現對父類具有可比性。
  4. 編寫您的實施。

解決方案應該是這樣的:

public abstract class MyClass implements ComparableFoo,Comparable<ComparableFoo> { 
    public int compareTo(ComparableFoo o) { 
    // your implementation 
    } 
} 

這種解決方案意味着更多的東西有可能實現的ComparableFoo - 這很可能並非如此,但那麼你的編碼到一個接口和仿製藥的表達很簡單。

+0

我喜歡這個解決方案,因爲它很簡單 – Pehmolelu 2015-08-24 06:14:46