Search code examples
javagenericswildcardcontravariancesupertype

How do supertype generics in Java work?


I've been testing supertype generics with Java, but I've come to a roadblock. This is the sample code I was testing:

import java.util.*;

class GenericTests {
    public static void main( String[] args ) {      
        List<B> list3 = new ArrayList<B>();
        testMethod( list3 );
    }

    public static void testMethod( List<? super B> list ) {
        list.add( new A() );
        list.add( new B() );
    }
}

class A { }

class B extends A { }

When compiled, the error is:

GenericTests.java:20: error: no suitable method found for add(A)
            list.add( new A() );
                ^
method List.add(int,CAP#1) is not applicable
  (actual and formal argument lists differ in length)
method List.add(CAP#1) is not applicable
  (actual argument A cannot be converted to CAP#1 by method invocation conve
rsion)
where CAP#1 is a fresh type-variable:
CAP#1 extends Object super: B from capture of ? super B
1 error

I thought that given the lower bound of B, you could add any supertype? Or does this only apply to the references (i.e. arguments within the method signature) because allowing supertypes would break the type checking?


Solution

  • The declaration List<? super B> list says that list is a List of objects of some type that B inherits from. But this type need not be compatible with A. Suppose the hierarchy had been:

    public class A {...}
    
    public class C extends A {...}
    
    public class B extends C {...}
    

    Then, list could be a List<C>. But then list.add(new A()) is illegal. An instance of A is not an instance of C. The compiler only knows that instances of B or a subclass can be added to list.