Java泛型双向引用



我正试图在java中创建两个相互包含的类之间的泛型关系。这些对象本质上形成了一个化身层树。到目前为止,我发现的最接近的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){...}
}

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

这主要涵盖了我想要的内容,因为我知道我可以获得一个组的项目的子组,并获得相同类型的组。但编译器不知道,如果我得到一个项的组的项,我会得到相同类型的项(例如,该项可能是孤立项)。此外,原始类型的警告总是让我觉得自己做错了什么。此外,如果有一种更好的方法来强制执行这种类绑定,我很想听听

您可以尝试以下操作:

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

最新更新