The concept of Polymorphism
doesn't extend to Java generics the same way as they do to classes. That's why, ConcurrentSkipListMap<Integer, ConcurrentSkipListMap<Integer, Integer>>
isn't considered as a subtype of Map<Integer, Map<Integer, Integer>>
and hence cannot be assigned.
The reason for this is that generics only provides compile-time type safety. At run-time the generic type is not known due to what is known as type erasure. So, basically compiler is trying to prevent this
// if this was allowed
List<Shape> shapes = new ArrayList<Circle>();
// and some place else in your code
shapes.add(new Square()); // Square now fits in a Circle list
This would break the ArrayList
's generic type and would throw no errors; because, which type is valid and which is not, isn't known at run-time. But, if you say, "Hey, that's what I want! Square
to go in a list of Shape
s." Then define the list so using new ArrayList<Shape>()
and the compiler would comply.
So, you just need to make your assignment as
Map<Integer, Map<Integer, Integer>> mmap =
new ConcurrentSkipListMap<Integer, Map<Integer, Integer>>();
i.e. preferring the use of Interfaces consistent on both the sides while using generics.
EDIT : (In response to @PaulBellora's downvote)
There's a reason why you can assign a Circle[]
to Shape[]
but not ArrayList<Circle>
to ArrayList<Shape>
. And, the reason is that if your code tries to add a Square
to a Circle[]
through a Shape[]
reference, you would get an ArrayStoreException
at runtime because JVM would know the actual type of the array.
But, due to type erasure the same runtime type safety cannot be extended to collections and hence generic types are not co-variant. If the question was why have the type erased then if knowing it at runtime could clearly have benefits; the answer would be to play nice with pre-Java 5 code base.