2014-01-10 3 views
6

나는 서로를 포함하고있는 두 클래스 사이에서 java에서 제네릭 관계를 생성하려고 시도하고있다. 객체는 필수적으로 alernating layer tree를 형성합니다. 지금까지 내가 발견 한 가장 가까운 SO 문제는 다음과 같습니다. Java generics of generics of. 제 문제에 가까와 다소 도움이되었지만 여전히 다른 지침을 원합니다. 게터와 세터를 넘어자바 제네릭 양방향 참조

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

와 괜찮 :이 뒤에 이유는 내가 클래스를 구현 한 경우, 그들은 다음과 같이 행동 할 것을 강제 할 것입니다 그룹의 항목 하위 그룹을 가져 와서 같은 그룹의 그룹을 다시 얻을 수 있다는 것을 알기 때문에 찾고 있습니다. 그러나 컴파일러는 항목의 그룹 항목을 가져 오는 경우 동일한 종류의 항목을 다시 가져올 것임을 알지 못합니다 (예 : 항목이 고아가 될 수 있음). 또한, 원시 타입 경고는 항상 내가 뭔가 잘못하고있는 것처럼 느낍니다. 또한 이런 종류의 클래스 바인딩을 강제하는 더 좋은 방법이 있다면, 나는 그것을 듣고 싶어 할 것입니다.

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