javabounded-wildcard

Upper bounded wildcards causing compilation error in Java


I cannot understand why I am getting these compilation errors:

1:

The method add(capture#1-of ? extends Exec.Bird) in the type List is not applicable for the arguments (Exec.Sparrow)

2:

The method add(capture#2-of ? extends Exec.Bird) in the type List is not applicable for the arguments (Exec.Bird)

static class Bird{}
static class Sparrow extends Bird{}

public static void main(String[] args){
    List<? extends Bird> birds = new ArrayList<Bird>();
    birds.add(new Sparrow()); //#1 DOES NOT COMPILE
    birds.add(new Bird());// //#2 DOES NOT COMPILE
}

Solution

  • With List<? extends Bird> you actually say any type that is a subtype of Bird, or, more accurately, an unknown, but specific type that is a subtype of Bird. It's not the same as saying every type that extends Bird.

    That means that ? can be a Sparrow, but it can also be a Blackbird. If you try to add a Sparrow to a list that could contain only Blackbirds, it won't work. For that same reason you cannot add a Bird to a list that could be a List of Sparrows.

    In order to make things work, you just change the declaration of the list to this:

    List<Bird> birds = new ArrayList<>();
    

    or use lower bound:

    List<? super Bird> birds = new ArrayList<>();
    

    About this lower bound example: the declaration actually says any type that is a Bird or one of its superclasses. That means that you can safely add a Sparrow or a Bird, because both meet those criteria.

    Generally speaking, you should use ? super ... when you are writing to the list, and ? extends ... when you are reading from the list. If you are both reading and writing, you shouldn't use bounds.


    This answer provides very useful information about generics. You definitely should read it.