What Are the Reasons Why Map.Get(Object Key) Is Not (Fully) Generic

What are the reasons why Map.get(Object key) is not (fully) generic

As mentioned by others, the reason why get(), etc. is not generic because the key of the entry you are retrieving does not have to be the same type as the object that you pass in to get(); the specification of the method only requires that they be equal. This follows from how the equals() method takes in an Object as parameter, not just the same type as the object.

Although it may be commonly true that many classes have equals() defined so that its objects can only be equal to objects of its own class, there are many places in Java where this is not the case. For example, the specification for List.equals() says that two List objects are equal if they are both Lists and have the same contents, even if they are different implementations of List. So coming back to the example in this question, according to the specification of the method is possible to have a Map<ArrayList, Something> and for me to call get() with a LinkedList as argument, and it should retrieve the key which is a list with the same contents. This would not be possible if get() were generic and restricted its argument type.

Why is java.util.Map.get(...) not generic?

The objects used to retrieve/remove/check for existance of a given key need not necessarily be of the same type as the object used to store it (= the key).

It needs to be equal and return the same hashCode as the key, but nothing in the spec says that it must be of the same type.

That fact is rarely used and most of the time you'll retrieve the values with the same keys (or at least objects of the same types) as the ones you use to store them.

But since that was a supported use case in the "old" HashMap, it needs to be supported in the generics version as well.

Note that all methods that keySet() uses the specific type, as it's sure to return exactly the objects used as keys when put() was called.

Java MapK,V : Why get(object) not get(K)?

Good explanations can be found in the answers of

What are the reasons why Map.get(Object key) is not (fully) generic

and

Java Generics: Why Does Map.get() Ignore Type?

Java Generics: Why Does Map.get() Ignore Type?

Kevin Bourrillion blogged about this a while ago. Summary:

Uniformly, methods of the Java
Collections Framework (and the Google
Collections Library too) never
restrict the types of their parameters
except when it's necessary to prevent
the collection from getting broken.

Personally I'm not a fan of that approach, but it does make some sense given the variance approach which has also been taken.

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

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.

Why Map.containsKey() takes an Object parameter instead of a speciallized type?

It's the same reason why you can't add anything to a List<? extends E> because the compiler can't guarantee the type safety (and type erasure makes a runtime check impossible).

This means that when you get a Map<? extends K,V> you wouldn't be able to call contains(K) on it. however contains is general enough that passing random Objects to it won't damage the interface (but makes some errors harder to pick up).



Related Topics



Leave a reply



Submit