我发现JDK 1.6及以上版本的HashMap类中的null keys部分代码与之前的JDK版本(如1.5)相比发生了变化。
在JDK1.5中,定义了一个名为NULL_KEY的static final Object:static final Object NULL_KEY = new Object();
方法,包括maskNull
、unmaskNull
、get
和put
等,都会用到这个对象。
见
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;
}
但是JDK 1.6以上版本不使用这种Object(NULL_KEY)
相反,添加了两个名为 getForNullKey()
和 putForNullKey(value)
的新方法,它们是也应用于 get
和 put
方法。
查看源码如下:
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;
}
变化总是有变化的原因,例如提高性能
等。请帮我解决以下2个问题
Q#1 ==> 为什么要进行此更改,是否存在 JDK 1.5 中实现的 HashMap 的空键遇到问题的情况?
Q#2 ==> JDK 1.6及以上版本HashMap的空键机制改变有什么好处?
最佳答案
Documentation for private V getForNullKey()说
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.
关于java - JDK 1.6及以上版本HashMap的空键机制改变有什么好处?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20218208/