HashMap HashTable ConcurrentHashMap key和value是否可以null的问题 源码分析

来源:互联网 发布:苹果电脑下不了软件 编辑:程序博客网 时间:2024/05/16 09:01

我们都知道结论是:

HashMap可以允许插入null key和null value

HashTable和ConcurrentHashMap都不可以插入null key和null value

具体原因可以看下面的源码:

首先是HashMap的put源码:

 

 public V put(K key, V value) {        if (table == EMPTY_TABLE) {            inflateTable(threshold);        }      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;    }

null key的情况,调用putForNullKey方法,之前我在博客上已经写过关于HashMap插入null key后的具体执行过程和源码分析了。

下面是HashTable的源码:

 public synchronized V put(K key, V value) {        // Make sure the value is not null       if (value == null) {            throw new NullPointerException();        }        // Makes sure the key is not already in the hashtable.        Entry tab[] = table;       int hash = hash(key);        int index = (hash & 0x7FFFFFFF) % tab.length;        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {            if ((e.hash == hash) && e.key.equals(key)) {                V old = e.value;                e.value = value;                return old;            }        }        modCount++;        if (count >= threshold) {            // Rehash the table if the threshold is exceeded            rehash();            tab = table;            hash = hash(key);            index = (hash & 0x7FFFFFFF) % tab.length;        }        // Creates the new entry.        Entry<K,V> e = tab[index];        tab[index] = new Entry<>(hash, key, value, e);        count++;        return null;    }

源码中判断了null value的情况,null value就抛出空指针异常异常

但是我们并没有看到判断null key然后抛出异常的语句,那么继续看看hash方法的源码就明白了:

private int hash(Object k) {        // hashSeed will be zero if alternative hashing is disabled.        return hashSeed ^ k.hashCode();    }

k.hashCode(),当k出入为null key 就会报错 空指针异常。

下面是ConcurrentHashMap的源码:

public V put(K key, V value) {        Segment<K,V> s;      if (value == null)            throw new NullPointerException();      int hash = hash(key);        int j = (hash >>> segmentShift) & segmentMask;        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment            s = ensureSegment(j);        return s.put(key, hash, value, false);    }

null value和null key 会报错的问题和HashTable原因是一样的,hash方法:

 private int hash(Object k) {        int h = hashSeed;        if ((0 != h) && (k instanceof String)) {            return sun.misc.Hashing.stringHash32((String) k);        }        h ^= k.hashCode();        // Spread bits to regularize both segment and index locations,        // using variant of single-word Wang/Jenkins hash.        h += (h <<  15) ^ 0xffffcd7d;        h ^= (h >>> 10);        h += (h <<   3);        h ^= (h >>>  6);        h += (h <<   2) + (h << 14);        return h ^ (h >>> 16);    }





1 0
原创粉丝点击