I found that some code is changed for null keys in class HashMap in JDK 1.6 or above version compared to the previous JDK version, like 1.5.
In JDK1.5, a static final Object named NULL_KEY is defined: static final Object NULL_KEY = new Object();
Methods, including maskNull
, unmaskNull
, get
and put
etc, will use this object.
See
static final Object NULL_KEY = new Object();
static <T> T maskNull(T key) {
return key == null ? (T)NULL_KEY : key;
}
static <T> T unmaskNull(T key) {
return (key == NULL_KEY ? null : key);
}
public V get(Object key) {
Object k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
Entry<K,V> e = table[i];
while (true) {
if (e == null)
return null;
if (e.hash == hash && eq(k, e.key))
return e.value;
e = e.next;
}
}
public V put(K key, V value) {
K k = maskNull(key);
int hash = hash(k);
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
if (e.hash == hash && eq(k, e.key)) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, k, value, i);
return null;
}
However, such Object (NULL_KEY) is not used in JDK 1.6 or above version.
Instead, two new methods named getForNullKey()
and putForNullKey(value)
is added, which are applied in get
and put
method as well.
See the source code as follows:
public V get(Object key) {
if (key == null)
return getForNullKey();
Entry<K,V> entry = getEntry(key);
return null == entry ? null : entry.getValue();
}
private V getForNullKey() {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null)
return e.value;
}
return null;
}
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
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))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
/**
* Offloaded version of put for null keys
*/
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}
Change always has its reason for changing, such as improving the performance
etc. Please help me out with the following 2 question
Q#1 ==> Why this change is made, is there some scenario that the null keys of HashMap implemented in JDK 1.5 encouneters issue ?
Q#2 ==> What is the advantage of null keys mechanism change of HashMap in JDK 1.6 or above version?
Indeed, if a Java Map implementation allows for null values, then it is possible for the Map to return its value for the given key, but that value might be a null. Often this doesn't matter, but if it does, one can use Map. containsKey() to determine if the Map entry has a key entry.
HashMap. get() method of HashMap class is used to retrieve or fetch the value mapped by a particular key mentioned in the parameter. It returns NULL when the map contains no such mapping for the key.
Yes, null is always a valid map key for any type of map key (including primitives, sobjects, and user-defined objects).
It returns a reference.
Documentation for private V getForNullKey() says
Offloaded version of get() to look up null keys. Null keys map to index 0. This null case is split out into separate methods for the sake of performance in the two most commonly used operations (get and put), but incorporated with conditionals in others.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With