简体   繁体   English

Java泛型2向引用

[英]Java generics 2-way reference

I'm attempting to create a generics relationship in java between two classes which contain each other. 我试图在java中创建两个相互包含的类之间的泛型关系。 The objects essentially form an alernating layer tree. 这些对象基本上形成一个alernating层树。 So far, the closest SO issue i found was this: Java generics of generics of , which was close and somewhat helpful for my issue, but still different enough that I'd like additional guidance. 到目前为止,我发现最接近的SO问题是: 泛型的Java泛型 ,它对我的​​问题很接近并且有些帮助,但仍然不同,我想要额外的指导。 Here's the situation or rather, what I'd like it to be: 这是情况,或者更确切地说,我希望它是什么:

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

Beyond the getters and setters, there are aspects of the class that make them notably different from each other, but the inclusion should follow like that. 除了吸气剂和制定者之外,该类的某些方面使它们彼此明显不同,但包含应该遵循这样的方式。 The reason behind this is that I want to enforce that if I have implementing classes, they have to behave like this: 这背后的原因是我想强制执行,如果我有实现类,他们必须表现如下:

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>

So far, the compiler is fine with 到目前为止,编译器很好用

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

This mostly covers what I'm looking for since I can know that I can get a group's items' child groups and get the same kind of group back. 这主要涵盖了我正在寻找的内容,因为我知道我可以获得一个小组的项目的子组并获得相同类型的组。 But the compiler don't know that if I get an item's groups' items I'll get the same kind of item back (for instance, the item could be an orphan). 但是编译器不知道如果我得到一个项目组的项目,我会得到相同类型的项目(例如,该项目可能是一个孤儿)。 Also, the raw types warning always makes me feel like I'm doing something wrong. 此外,原始类型警告总是让我觉得我做错了什么。 Also also, if there's a better way of enforcing this kind of class binding, I'd be interested to hear it. 另外,如果有更好的方法来强制执行这种类绑定,我会有兴趣听到它。

You could try the following: 您可以尝试以下方法:

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 ) 意见

The reason for using two type parameters is that since each type is parameterized with a type that does the opposite, each needs to keep track of both the other's type and its own "self type". 使用两个类型参数的原因是,由于每个类型都使用相反的类型进行参数化,因此每个类型都需要跟踪另一个类型和它自己的“自我类型”。

This can be generalized to an arbitrary number of "participating" types: 这可以推广到任意数量的“参与”类型:

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

However the use and implementation of these kinds of recursive generics tend to be overly complicated and seldom very beneficial (I describe one use case on this post: Is there a way to refer to the current type with a type variable? ). 然而,这些类型的递归泛型的使用和实现往往过于复杂而且很少有用(我在这篇文章中描述了一个用例: 有没有办法用类型变量引用当前类型? )。 It might be better to step back and reevaluate your design to see whether this two-way generic relationship is really necessary. 退一步并重新评估您的设计可能会更好,看看这种双向通用关系是否真的有必要。 More often than not I've found that recursive generics arise out of a type that's trying to do too much and whose responsibilities should be decoupled into multiple simpler types. 通常情况下,我发现递归泛型是出于一种试图做太多而且其责任应该分解为多种更简单类型的类型。

If you'd define the groups and items like this, it should get you a step farther: 如果您要定义这样的组和项目,它应该让您更进一步:

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

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

This should result in the following: 这应该导致以下结果:

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