5

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);
Win Man
  • 929
  • 2
  • 15
  • 30
  • The compiler should warn you about the cast being unsafe, (List) will compile to (List) which wont throw a class cast exception if your list is a List and may cause class cast exceptions in other parts of your code if you insert objects – josefx Jan 08 '10 at 00:14
  • SO members demystified this exact case earlier for me. Though you have accepted an answer you might still want to check this out: [Why is passing a subclass to a bounded wildcard only allowed in certain places?](https://stackoverflow.com/questions/1845276/why-is-passing-a-subclass-to-a-bounded-wildcard-only-allowed-in-certain-places) – Murali Jan 07 '10 at 23:58

2 Answers2

13

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.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
-1

Its a nullable type like so:

http://msdn.microsoft.com/en-us/library/1t3y8s4s%28VS.80%29.aspx

EDIT: I must be wrong so, given the two answers above! Sorry!

deanvmc
  • 5,957
  • 6
  • 38
  • 68
  • Wrong language, and nothing to do with nullability. In C# this would be completely incorrect syntax. – Jon Skeet Jan 07 '10 at 23:49
  • I figured that after posting and edited, sorry new to stack overflow its my first time on a multi-language forum. – deanvmc Jan 07 '10 at 23:50