Demystify Wildcard for me

generics, java, wildcard

Solution

The wildcard "? extends Location" means "I want it to be `List<T>` for some `T` where `T` is a subclass of `Location` (or is `Location` itself)."

Now, let's leave that to one side for a second. Would you expect this to compile:

List<String> strings = new List<String>();
strings.add(new Object());

? I wouldn't think so - you can't add a bare "object" to a list of strings. Any item in a list of strings has to be a string.

Go back to your first thing. Suppose `locationsTypeMap.get(key)` returns an object which is (logically - ignore type erasure for now) a `List<ExoticLocation>` - but suppose newLocation is actually an instance of `BoringLocation`. You shouldn't be able to add a `BoringLocation` to a `List<ExoticLocation>` and the compiler knows that - so it stops that from happening.

Anything you get from a `List<? extends Location>` is guaranteed to be a `Location` of some kind... but you can't add anything to it. The reverse is true with `super`: you can't guarantee that anything you get from a `List<? super Location>` will be a `Location`, but you can add a `Location` to it.

To give a very different example: is a bunch of bananas a collection of fruit? Well it is in one sense - anything you get from it is a fruit. But it's not in another, because you can't add any old kind of fruit to it - if you try to add an apple, it'll fall off :)

See Angelika Langer's Java Generics FAQ for a lot more information.

Problem

Why do I get a compile time error on this piece of code? ``` public Interface Location { ....... } ``` Class code... ``` Map<Type, List<? extends Location>> locationsTypeMap = new HashMap<Type, List<? extends Location>>(); /** Code to add elements to the hashMap. */ newLocation = getNewLocation() while(mapHasElements){ Location.Type key = location.getType(); List<? extends Location> valueList = (List<? extends Location>)locationsTypeMap.get(key); //1 valueList.add(newLocation);/*Compile error*/ } ``` On the other hand, if I replace step 1 with line below it works ``` List<Location> valueList = (List<Location>)locationsTypeMap.get(key); ```

Original source