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);
The wildcard “? extends Location” means “I want it to be
List<T>for someTwhereTis a subclass ofLocation(or isLocationitself).”Now, let’s leave that to one side for a second. Would you expect this to compile:
? 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) aList<ExoticLocation>– but suppose newLocation is actually an instance ofBoringLocation. You shouldn’t be able to add aBoringLocationto aList<ExoticLocation>and the compiler knows that – so it stops that from happening.Anything you get from a
List<? extends Location>is guaranteed to be aLocationof some kind… but you can’t add anything to it. The reverse is true withsuper: you can’t guarantee that anything you get from aList<? super Location>will be aLocation, but you can add aLocationto 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.