Search code examples
javagenericspolymorphismtype-parameter

Java Generics & Polymorphism


I had an error while generalizing some classes in order to reduce code duplicates in my project, the case is as follows:

interface ClassRoot{}

public class ClassChild1 implements ClassRoot{
    // constructor is omitted for simplicity
    public Collection<ClassChild1> createList(){

        Collection<ClassChild1> col = getCollectionFromSomewhere();
        return col;
    }
}

public class Class1{
    protected <T extends ClassRoot> Collection<T> doSth(){
        Collection<T> myCol = null;
        ClassChild1 child = new ClassChild1();

        // here I get compile time assignment error
        // also (assuming that myCol not null) myCol.add(new ClassChild1());
        // is not permitted.
        myCol = child.createList();
        return myCol;
    }
}

Isn't that against the polymorphism phenomenon? I know that for example,

List<Object> list1;

can never be (and should not be assigned for typesafety) to:

List<String> list2;

But here my case is different, i specified the Type Parameter extending some specific class expecting to make use of OOP Polymorphism concept, and doing assignments right exactly implementing right class. Now I have 2 questions;

  • May someone clearly explain why is that is forbidden in Java, for what justifiable reason?
  • How can I implement such a functionality, by using type params or wildcards?

Solution

  • The assignment

    Collection<T> myCol = null;
    myCol = child.createList();
    

    will fail because you are assigning Collection<ClassChild1> to a Collection parameterized with an unknown type T, which may or may not be ClassChild1.

    You have specified T as inferred at the call site, so imagine the following code:

    Class1 c1;
    Collection<ClassChild2> c = c1.doSth();
    

    You can see that the compiler would paint itself into a corner if it allowed you to compile such a doSth method since inside that method you want to add a ClassChild1 instance to a collection that in this example happens to hold instances of ClassChild2.