What are the reasons why Map.get(Object key) is not (fully) generic
Solution 1:
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.
Solution 2:
An awesome Java coder at Google, Kevin Bourrillion, wrote about exactly this issue in a blog post a while ago (admittedly in the context of Set
instead of Map
). The most relevant sentence:
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.
I'm not entirely sure I agree with it as a principle - .NET seems to be fine requiring the right key type, for example - but it's worth following the reasoning in the blog post. (Having mentioned .NET, it's worth explaining that part of the reason why it's not a problem in .NET is that there's the bigger problem in .NET of more limited variance...)
Solution 3:
The contract is expressed thus:
More formally, if this map contains a mapping from a key k to a value v such that (key==null ? k==null : key.equals(k)), then this method returns v; otherwise it returns null. (There can be at most one such mapping.)
(my emphasis)
and as such, a successful key lookup depends on the input key's implementation of the equality method. That is not necessarily dependent on the class of k.