4

Why doesn't that work in java, but this does

Map<String, Map<String, Boolean>> myMap = new HashMap<String,Map<String,Boolean>>();

Just to clarify the below alteration of the nested HashMap shows a compiler error, whereas the above does not not; with a Map (not hashmap)

Map<String, Map<String, Boolean>> myMap = new HashMap<String,HashMap<String,Boolean>>();
NimChimpsky
  • 46,453
  • 60
  • 198
  • 311

3 Answers3

10

This is because generics in Java are invariant, i.e. even if class B is an A, a Collection<B> is not a Collection<A>.

And this is for a good reason. If your example were legal, this would be possible:

Map<String, HashMap<String, Boolean>> myHashMap = new HashMap<String,HashMap<String,Boolean>>();
Map<String, Map<String, Boolean>> myMap = myHashMap;
myMap.put("oops", new TreeMap<String, Boolean>());
HashMap<String, Boolean> aHashMap = myMap.get("oops"); // oops - ClassCastException!
Péter Török
  • 114,404
  • 31
  • 268
  • 329
  • But, given the declaration of myMap, what would I care what kind of Maps are put in there as long as they implement the Map interface? – extraneon Sep 03 '10 at 14:52
  • @extraneon: In that case, see Boris's answer. – Powerlord Sep 03 '10 at 14:56
  • Java generics can have use-side variance, but not declaration-side variance. (The latter makes sense for languages where it is idiomatic for interfaces to be either "tell don't ask" or are immutable.) – Tom Hawtin - tackline Sep 03 '10 at 16:41
  • I understand the why from a technical point of view, it made the implementation of generics easier. But from a functional point of view it's not all that logical. If I say (which I can't do) that my map contains map values, than I also commit to not getting a specific type of map out of there. But I can't say this map contains maps, but it must contain a specific type of map. And this is, to me, a compromise to make implementation of generics feasible, and not a feature :) – extraneon Sep 04 '10 at 09:08
  • @extraneon, this specific example with maps is a bit contorted; see [this earlier answer of mine](http://stackoverflow.com/questions/2292308/generics-method-signatures-assignments/2292339#2292339) for a simpler and (hopefully) more revealing example. – Péter Török Sep 04 '10 at 11:50
5

In the second case myMap is a map which keys are of type String and values are of type Map<String, Boolean>. HashMap<String, Boolean> is not a Map<String, Boolean> it implements it. Therefore, this will compile:

Map<String, ? extends Map<String, Boolean>> myOtherMap = 
    new HashMap<String,HashMap<String,Boolean>>();
Boris Pavlović
  • 63,078
  • 28
  • 122
  • 148
-1

I think that's because of the difference between Map<String, Boolean> and HashMap<String,Boolean>. Indeed, the generics are here a specification, which must be the same on both sides. (or at least that's my opinion).

Riduidel
  • 22,052
  • 14
  • 85
  • 185