Reputation: 46841
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
Upvotes: 4
Views: 3327
Reputation: 718758
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.
Upvotes: 5
Reputation: 1622
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
.
Upvotes: 0
Reputation: 6871
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.
Upvotes: 0
Reputation: 7692
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;
}
Upvotes: 2