Home > Back-end >  Java Generics not accepting class that extends parent with correct type
Java Generics not accepting class that extends parent with correct type

Time:08-02

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.

  • Related