2014-01-10 74 views
6

我試圖在兩個包含對方的類之間的Java中創建泛型關係。這些對象本質上構成了一個漸變層樹。到目前爲止,我發現的最接近的SO問題是這樣的:Java generics of generics of,這對我的問題來說很接近並且有點幫助,但仍然不同,所以我想要額外的指導。這裏的情況或者說,想什麼我它是:Java泛型2路參考

abstract class Group<I extends Item<Group<I>>>{ 
    private List<I> items; 
    public List<I> getItems(){...} 
    public void setItems(List<I> items){...} 
} 

abstract class Item<G extends Group<Item<G>>>{ 
    private List<G> subGroups; 
    public List<G> getSubGroups(){...} 
    public void setSubGroups(List<G> subGroups){...} 
} 

除了getter和setter方法,有使它們彼此明顯不同類的方面,但列入應遵循這樣的。這背後的原因是,我想強制執行,如果我已經實現類,他們的行爲是這樣的:

class AGroup extends Group<AItem>{...} //works 
class AItem extends Item<AGroup>{...} //works 
class BGroup extends Group<BItem>{...} //works 
class BItem extends Item<BGroup>{...} //works 
class MixedGroup extends Group<AItem>{...} //fails since AItem does 
              //not extend Item<MixedGroup> 

到目前爲止,編譯器是罰款

abstract class Group<I extends Item<Group<I>>>{ 
    private List<I> items; 
    public List<I> getItems(){...} 
    public void setItems(List<I> items){...} 
} 

abstract class Item<G extends Group>{ //raw types warning 
    private List<G> subGroups; 
    public List<G> getSubGroups(){...} 
    public void setSubGroups(List<G> subGroups){...} 
} 

這主要包括什麼我在找,因爲我可以知道我可以得到一個組的物品的孩子組,並獲得相同類型的組。但編譯器不知道,如果我得到一個項目的組的項目,我會得到相同類型的項目(例如,該項目可能是一個孤兒)。此外,原始類型警告總是讓我覺得我做錯了什麼。另外,如果有更好的方法來執行這種類的綁定,我很樂意聽到它。

+1

相關閱讀:[週期性泛型(嘗試2)](http://stackoverflow.com/questions/9423047/cyclical-generics-try-2) –

回答

6

你可以嘗試以下方法:

abstract class Group<I extends Item<I, G>, G extends Group<I, G>> { 
    private List<I> items; 
    public List<I> getItems() { return null; } 
    public void setItems(List<I> items) { } 
} 

abstract class Item<I extends Item<I, G>, G extends Group<I, G>> { 
    private List<G> subGroups; 
    public List<G> getSubGroups() { return null; } 
    public void setSubGroups(List<G> subGroups) { } 
} 

class AGroup extends Group<AItem, AGroup> { }   // works 
class AItem extends Item<AItem, AGroup> { }   // works 
class BGroup extends Group<BItem, BGroup> { }   // works 
class BItem extends Item<BItem, BGroup> { }   // works 
class MixedGroup extends Group<AItem, MixedGroup> { } // fails 

ideone

之所以使用兩個類型參數是因爲每個類型參數與類型則正好相反,每個需要保持追蹤對方的類型和自己的「自我類型」。

這可以概括爲的「參與」類型的任意數目:

// one type 
interface SelfParameterized<T extends SelfParameterized<T>> { } 

// two types 
interface SelfParameterizedPairA< 
     A extends SelfParameterizedPairA<A, B>, 
     B extends SelfParameterizedPairB<A, B> 
> { } 
interface SelfParameterizedPairB< 
     A extends SelfParameterizedPairA<A, B>, 
     B extends SelfParameterizedPairB<A, B> 
> { } 

// three types 
interface SelfParameterizedTrioA< 
     A extends SelfParameterizedTrioA<A, B, C>, 
     B extends SelfParameterizedTrioB<A, B, C>, 
     C extends SelfParameterizedTrioC<A, B, C> 
> { } 
interface SelfParameterizedTrioB< 
     A extends SelfParameterizedTrioA<A, B, C>, 
     B extends SelfParameterizedTrioB<A, B, C>, 
     C extends SelfParameterizedTrioC<A, B, C> 
> { } 
interface SelfParameterizedTrioC< 
     A extends SelfParameterizedTrioA<A, B, C>, 
     B extends SelfParameterizedTrioB<A, B, C>, 
     C extends SelfParameterizedTrioC<A, B, C> 
> { } 

然而,這些類型的遞歸仿製藥的使用和實施往往是過於複雜,很少是非常有益的(我描述一個使用在這個職位上的案例:Is there a way to refer to the current type with a type variable?)。最好退一步,重新評估你的設計,看看這種雙向通用關係是否真的有必要。 More often than not我發現遞歸泛型產生於一種嘗試做得太多的類型,其責任應該分解成多個更簡單的類型。

+0

一個很好的和廣泛的答案。謝謝。 – Thomas

1

如果要定義組,這樣的項目,它應該讓你更遠了一步:

abstract class Group<I extends Item<? extends Group<I>>> 

abstract class Item<G extends Group<? extends Item<G>>> 

這將導致如下:

class AGroup extends Group<AItem>{} 
class AItem extends Item<AGroup>{} 

//doesn't work since the item could only be added to MixedGroup instances 
//but MixedGroup only accepts AItem instances 
class MixedItem extends Item<MixedGroup>{} 

//works since the item might be added to any AGroup 
class MixedItem2 extends Item<AGroup>{} 

//works, since AItem can be added to any AGroup (and MixedGroup is a Subclass) 
class MixedGroup extends Group<AItem> {}