0

I have no idea why I can pass any type of value to the HashMap.containsKey() method. I assume this method is an instance method (correct me if I am wrong) of HashMap Class which should be constrained by generic typing. If JAVA doesn't want to constrain it , why does the HashMap.put() method need to match the type it is parameterized with ...

    HashMap<String, String> map = new HashMap<String, String>();
    // invalid
    // map1.put(1, "a");

I can't put int value key to my HashMap map having the key type of String. What is different between both the containsKey() and put() methods ?

public static void main(String[] args) {
    HashMap<String, String> map1 = new HashMap<String, String>();
    map1.put("1", "a");
    map1.put("2", "b");
    map1.put("3", "c");
    if (map1.containsKey(1)) {
        System.out.println("contain");
    }
    else {
        System.out.println("not contain");
    }
}

In the above code,not contain was output, and the compiler didn't object. If it did, It would prevent this mistake from happening! Am I right? If not, please guide me to the truth.
Thanks for reading my question!

Azar
  • 1,086
  • 12
  • 27
Cataclysm
  • 7,592
  • 21
  • 74
  • 123

3 Answers3

2

The answer revolves around PECS, a concept I explain here.

The short story is that with Map<?, ?>, I cannot call Map.containsKey(K) with the generic parameter, even though it technically isn't a consumer method. By making it Map.containsKey(Object), I can call containsKey no matter what the type is, which is useful in wildcard-bound maps.

Community
  • 1
  • 1
Brian
  • 17,079
  • 6
  • 43
  • 66
1

You'll note that in the Javadoc for HashMap Map.containsKey() takes an Object as its argument. The class was added in Java 1.2 prior to generics, and when generics were added in 1.5 the method signature wasn't changed.

This means when you do:

if (map1.containsKey(1)) {

1 gets autoboxed to an Integer object. Then during the key lookup, the hashcode() method is called for that Integer object to see if it exists in the Map. And ... it doesn't.

You would need to convert that int to a String for it to work correctly given your Map<String,String>:

if (map1.containsKey(String.valueOf(1)) {
Brian Roach
  • 76,169
  • 12
  • 136
  • 161
  • This isn't true. If this were the case, why would they change `get(Object)` to `get(K)` in the `Map` interface? – Brian Mar 19 '14 at 15:35
  • @Brian Re-reading what I wrote originally re: generics you're correct. I think I really meant to type classes rather than interfaces but even that's prob not entirely accurate. But since that wasn't really the important part of the answer in the first place ... edited. – Brian Roach Mar 19 '14 at 16:37
-1

The containsKey method has the following signature :

public boolean containsKey(Object key).

So when you pass it an int , it uses the argument's equals method to determine equality. As your keys are Strings , "1".equals(1) returns false.

Tejas Kale
  • 415
  • 8
  • 18