I'm trying to create a few structure classes so I can easily build a structure but the generics don't accept the class even though it seems to have the right type.
I have a basic Structure
class that just stores a parent of the generic type T
:
public abstract class Structure<T>{...}
Then I have a KeyedStructure
that stores both a key of type K
and extends Structure
with type V
:
public abstract class KeyedStructure <K, V> extends Structure<V>{...}
Finally, I have a KeyedBidirectionalStructure
class that has types <K, PARENT, CHILD>
but the CHILD
has to be able to store this class as its parent so it extends KeyedStructure<K, KeyedBidirectionalStructure<K, PARENT, CHILD>>
:
public abstract class KeyedBidirectionalStructure<K, PARENT, CHILD extends KeyedStructure<K, KeyedBidirectionalStructure<K, PARENT, CHILD>>> extends KeyedStructure<K, PARENT>{...}
But when I try to implement it like this:
class Group extends KeyedBidirectionalStructure<String, Group, Group>{...}
or even like this
class Task extends KeyedStructure<String, Group>{...}
class Group extends KeyedBidirectionalStructure<String, Group, Task>
Java keeps complaining that the CHILD
type does extend the right class but it seems to fit the generics. If anyone could help me that would be greatly appreciated. Thank you.
CodePudding user response:
Your declaration of Group
extends KeyedBidirectionalStructure
with the third type argument (for CHILD
) being Group
. So this Group
needs to satisfy the bound of CHILD
, which, with everything substituted in, is extends KeyedStructure<String, KeyedBidirectionalStructure<String, Group, Group>>
. But it doesn't satisfy this. Group
extends KeyedBidirectionalStructure<String, Group, Group>
which in turn extends KeyedStructure<String, Group>
. Do you see the difference? In one case, the second type argument is Group
, and in the other, the second type argument is KeyedBidirectionalStructure<String, Group, Group>
. They don't match.
Generic type arguments are invariant. List<String>
is not a subtype of List<Object>
even though String
is a subtype of Object
. So similarly KeyedStructure<String, Group>
is not a subtype of KeyedStructure<String, KeyedBidirectionalStructure<String, Group, Group>>
, even though Group
is a subtype of KeyedBidirectionalStructure<String, Group, Group>
.
If you want polymorphism in the type arguments, you need to use a wildcard. So if you changed the bound to something like this, your declaration of Group
should work:
public abstract class KeyedBidirectionalStructure<K, PARENT,
CHILD extends KeyedStructure<K, ? extends KeyedBidirectionalStructure<K, PARENT, CHILD>>>
extends KeyedStructure<K, PARENT> {...}
However, there are other consequences of using a wildcard, and I am not sure if it makes sense without understanding your full design.