繁体   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