簡體   English   中英

Java泛型2向引用

[英]Java generics 2-way reference

我試圖在java中創建兩個相互包含的類之間的泛型關系。 這些對象基本上形成一個alernating層樹。 到目前為止,我發現最接近的SO問題是: 泛型的Java泛型 ,它對我的​​問題很接近並且有些幫助,但仍然不同,我想要額外的指導。 這是情況,或者更確切地說,我希望它是什么:

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){...}
}

除了吸氣劑和制定者之外,該類的某些方面使它們彼此明顯不同,但包含應該遵循這樣的方式。 這背后的原因是我想強制執行,如果我有實現類,他們必須表現如下:

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){...}
}

這主要涵蓋了我正在尋找的內容,因為我知道我可以獲得一個小組的項目的子組並獲得相同類型的組。 但是編譯器不知道如果我得到一個項目組的項目,我會得到相同類型的項目(例如,該項目可能是一個孤兒)。 此外,原始類型警告總是讓我覺得我做錯了什么。 另外,如果有更好的方法來強制執行這種類綁定,我會有興趣聽到它。

您可以嘗試以下方法:

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

意見

使用兩個類型參數的原因是,由於每個類型都使用相反的類型進行參數化,因此每個類型都需要跟蹤另一個類型和它自己的“自我類型”。

這可以推廣到任意數量的“參與”類型:

// 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>
> { }

然而,這些類型的遞歸泛型的使用和實現往往過於復雜而且很少有用(我在這篇文章中描述了一個用例: 有沒有辦法用類型變量引用當前類型? )。 退一步並重新評估您的設計可能會更好,看看這種雙向通用關系是否真的有必要。 通常情況下,我發現遞歸泛型是出於一種試圖做太多而且其責任應該分解為多種更簡單類型的類型。

如果您要定義這樣的組和項目,它應該讓您更進一步:

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> {} 

暫無
暫無

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

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