Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why HashMap with generic declaration "<? super ArrayList> does not accept value "new Object()" in the put method?

While working on interview questions, I have come across below code:

List<Object> list = new ArrayList();
Map<Object, ? super ArrayList> m = new HashMap<Object,  ArrayList>();
m.put(1, new Object());
m.put(2, list);

The above two put method's are throwing compile time error. But, when I add m.put(3, new ArrayList()); it is adding to map with no compile time error.

It is very clear for me that I can add new Object() as a value in HashMap because of the map declaration to be of type < ? super ArrayList>; it means I can add any value that is higher than ArrayList (i.e. super of ArrayList) and ArrayList object too, but not anything below ArrayList.

This particular concept is very well written in SCJP 6 by Kathy Sierra and Bert Bates and based on that theory and examples I assumed it should do job as I understood. Can someone help me understand the error?

like image 580
MKod Avatar asked Jan 03 '15 11:01

MKod


People also ask

Can the value of a HashMap be an ArrayList?

A HashMap contains key-value pairs, there are three ways to convert a HashMap to an ArrayList: Converting the HashMap keys into an ArrayList. Converting the HashMap values into an ArrayList. Converting the HashMap key-value pairs into an ArrayList.

Can HashMap use generic types?

The term generic simply is the idea of allowing the type (Integer, Double, String, etc. or any user-defined type) to be the parameter to methods, class, or interface. For eg, all the inbuilt collections in java like ArrayList, HashSet, HashMap, etc. use generics.

Is HashMap better than ArrayList?

Both are better based on your requirements, if you need to store a set of similar objects in a list like data structure then ArrayList is better and if you want to store key and value pair HashMap is better.


2 Answers

The type ? super ArrayList means an unknown type, which has a lower bound of ArrayList. For example, it could be Object, but might be AbstractList or ArrayList.

The only thing the compiler can know for sure is that the type of the value, although unknown, is guaranteed to be no more specific than ArrayList, so any object that is an ArrayList, or a subclass of ArrayList, may be added.

Also remember: the compiler only goes by the declared type; it ignores the assigned type.

Why put(1, new Object()) fails:

Clearly, Object is not within bounds.

Why put(1, list) fails:

The variable is of type List, which may hold a reference to a LinkedList, which is not within the required bounds.

like image 24
Bohemian Avatar answered Sep 21 '22 16:09

Bohemian


You are misunderstanding what the wildcard ? means. You probably have a common misconception:

It does not mean that you can put any kind of object in the map which is of a type that is a superclass of ArrayList.

What it means is that the values in the map are of some unknown type that is a supertype of ArrayList. Since the exact type is not known, the compiler won't allow you to put a value of any type other than ArrayList itself as a value in the map - the compiler does not have enough information to check if what you are doing is type-safe.

Suppose that this was allowed, then you could do bad things like this:

Map<Object, ArrayList> m1 = new HashMap<Object, ArrayList>();

Map<Object, ? super ArrayList> m2 = m1;

// This should not be allowed, because m2 is really a HashMap<Object, ArrayList>
m2.put(1, new Object());
like image 197
Jesper Avatar answered Sep 20 '22 16:09

Jesper