java - JDK 1.6及以上版本HashMap的空键机制改变有什么好处?

标签 java hashmap

我发现JDK 1.6及以上版本的HashMap类中的null keys部分代码与之前的JDK版本(如1.5)相比发生了变化。

在JDK1.5中,定义了一个名为NULL_KEY的static final Object:static final Object NULL_KEY = new Object();

方法,包括maskNullunmaskNullgetput等,都会用到这个对象。

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) 的新方法,它们是也应用于 getput 方法。

查看源码如下:

 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/

相关文章:

java - 如何在 UIManager 中使用默认的 Nimbus 颜色?

java - 如何合并列表,保留每个人的顺序?

android - 用于在 Activity 之间传递数据的 WeakReferences 的 HashMap

java - 在java中检索列表中的行值(来自Postgresql)

java - 两个线程并发修改HashMap

java - 如何在具有不同java版本的wildfly服务器上运行两个Web应用程序?

java - 编译器使用关联性有什么问题?

散列的散列的 Ruby 散列

java - Hashmap员工存储的编辑方法

java - 关于Java中基数排序实现的问题