Search code examples
javagenericsgeneric-programming

complementary generic classes


I have two abstract classes: Container, Node

One kind of Container will always contain the same kind of Node, and one kind of node will only belong to its corresponding container: NodeTypeA is stored in ContainerTypeA, and no other subclass of Node is stored in it. NodeTypeB is stored in ContainerTypeB, and no other subclass of Node is stored in it. The back-reference from the Node to its Container should also be aware of the type of the Container, so the relation goes in both directions.

I have problems implementing this in Java.

I do it like this:

Container<C extends Container<C,N>, N extends Node<C,N>>
Node<C extends Container<C,N>, N extends Node<C,N>>

However, when I define the following field in Container, I get an error:

private List<N> nodes;

The error message says that I should replace N with Node. This seems redundant to me. Why does this happen, and how can I get the program to understand that

N

should be equal to

Node<C,N>

Test case:

https://ideone.com/wam0gi

The purpose behind this:

There are many different kinds of Nodes and many different kinds of ways in which they can interact. However, they share some common themes. Container and Node should be abstract classes within which I can define methods and abstract methods to define these common themes. ContainerA and NodeA together will then define one particular method of interaction. I use generics for this because programming gets a lot easier if my IDE is smart enough to know that any Node in a ContainerA is always a NodeA, and the owner of a NodeA is always a ContainerA, so I can avoid some unnecessary type-casting.

(Note: this question is similar but not equal to Complementary generic types)


Solution

  • Aside from several trivial errors (abstract should precede class in java, wrong type variable L in constructor of Node at line 16, attempt to access a private field at line 18), your semantic problem is at line 18. The type of this is Node<C,N>, not N.

    One way to achieve your goal is to add an abstract method to Node which returns N, and all subclasses will implement it by returning this.

    abstract protected N me();
    

    Then, once you've added a proper setter to Container, you'll change line 18 to

    owner.add( me() );