4

How HashMap internally differentiate between null and 0 as key.

As per this post the hash code for null key is 0, Is it correct? If yes then both should go in same bucket at index 0 and there should be one value in the HashMap but this is not how HashMap works.

Can somebody explain me? what is the hash code for null key in HashMap?

Sample code:

HashMap<Integer,String> map=new HashMap<Integer,String>();
map.put(null, "abc");
map.put(0, "xyz"); // will it override the value for null as key?

System.out.println(map.get(null));  // abc
System.out.println(map.get(0));     // xyz
Community
  • 1
  • 1
Braj
  • 46,415
  • 5
  • 60
  • 76
  • 1
    Hash codes are not unique - it doesn't matter that the hash code for `null` is `0` or any other value. There is not one value per hash code in a hash map. – Jesper Sep 06 '14 at 07:02
  • @Jesper Will it check for `equals()` if `hashCode()` returns same value? If yes then how it will work in this case? – Braj Sep 06 '14 at 07:04
  • 1
    Yes, but `null` is ofcourse handled in a special way, to avoid a `NullPointerException` from happening. If you really want to know all the implementation details, lookup the source code of `HashMap` which you can find in `src.zip` in your JDK installation directory. – Jesper Sep 06 '14 at 07:05
  • When fetching a key, all nodes with the same hashCode will be compared using equals to the given key until one matchs. For null, there is a conditional in the implementation: if (key == null) – JosEduSol Sep 06 '14 at 07:06
  • so the answer is `HashMap` handles `null` in special way. – Braj Sep 06 '14 at 07:08

4 Answers4

5

If yes then both should go in same bucket at index 0 ...

Correct.

and there should be one value in the HashMap

Incorrect. There will be a separate entry for the two keys. This is guaranteed by the Map and HashMap specification; i.e. the javadocs say that there will be a separate entry for each distinct key. The implementation is required to meet the specification ... and it does.

Prior to Java 8, the way that HashMap handles collisions is to chain together all of the entries that hash to the same bucket. The HashMap.get(key) logic will iterate the chain for the relevant bucket, looking for an entry that matches the key. (In your example code, there would be separate entries in the chain for the null and the Integer(0) keys.)

In Java 8, it works the same to start with, but there is an optimization for the case where the keys all implement Comparable and the chains get too long. In this case, the long chains are converted into binary trees ... so that an O(N) chain scan turns into an O(logN) tree search.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • yes that's correct but how it works in that case. Please explain a bit more. If both have same hash code in that case the value should be overridden by last one. Isn't it? – Braj Sep 06 '14 at 06:49
  • _No._ Just because keys end up in the same bucket, or have the same hash code, does _not_ mean they override each other. Only if they're equal according to `Object.equals` to keys override each other. – Louis Wasserman Sep 06 '14 at 16:37
2

Both cases belongs to hashCode()==0 but equals differs hence two entries and both get return associated values.

Case with null:

public V put(null,"abc") {    
         if (key == null)
                    return putForNullKey(value);
}
private V putForNullKey(V value) {
        ..
        addEntry(0, null, value, 0); ==> 0th index with 0 hashCode
        return null;
    }

Case with 0:

public V put(K key, V value) {       
        int hash = hash(key.hashCode()); ==> 0
        int i = indexFor(hash, table.length); ==> 0
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { ==> false
                ..
            }
        }

        modCount++;
        addEntry(hash, key, value, i); ==> addition to link list
        return null;
    }
harsh
  • 7,502
  • 3
  • 31
  • 32
  • static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } I didnt seen any putForNullKey method in it .. it will just put zero for all null keys .. after decompiling code of hashmap – Luckyman Nevermore Feb 01 '21 at 15:59
0

You may have some mistakes with hash.

1, when the key is 0, the hash code is may not 0. Because the hash code is:

final int hash(Object k) {
    int h = hashSeed;
    if (0 != h && k instanceof String) {
        return sun.misc.Hashing.stringHash32((String) k);
    }
    h ^= k.hashCode();
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

2, when your key is null, the JDK call a special method to do,

 if (key == null)
    return putForNullKey(value);

Yes, when key is null, the hash is 0. If you want know more, please see the JDK source code.

chenzhongpu
  • 6,193
  • 8
  • 41
  • 79
0

This is possible because single Entry in the HashMap is not just key-value pair but also has a next field, so it's sort of simple linked list and adding of new entry looks as follows:

void createEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<>(hash, key, value, e);
    size++;
}

e local variable (the one that was already present) ends up as the next value in the Entry for given hash and bucketIndex.

MirMasej
  • 1,592
  • 12
  • 17