HashMap HashTable ConcurrentHashMap key和value是否可以null的問題 源碼分析

我們都知道結論是:

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

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

具體原因可以看下面的源碼:

首先是HashMap的put源碼:

 

[java] view plain copy
  1. public V put(K key, V value) {  
  2.        if (table == EMPTY_TABLE) {  
  3.            inflateTable(threshold);  
  4.        }  
  5.      if (key == null)  
  6.            return putForNullKey(value);  
  7.        int hash = hash(key);  
  8.        int i = indexFor(hash, table.length);  
  9.        for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
  10.            Object k;  
  11.            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
  12.                V oldValue = e.value;  
  13.                e.value = value;  
  14.                e.recordAccess(this);  
  15.                return oldValue;  
  16.            }  
  17.        }  
  18.   
  19.        modCount++;  
  20.        addEntry(hash, key, value, i);  
  21.        return null;  
  22.    }  

null key的情況,調用putForNullKey方法,之前我在博客上已經寫過關於HashMap插入null key後的具體執行過程和源碼分析了。

下面是HashTable的源碼:

[java] view plain copy
  1. public synchronized V put(K key, V value) {  
  2.        // Make sure the value is not null  
  3.       if (value == null) {  
  4.            throw new NullPointerException();  
  5.        }  
  6.   
  7.        // Makes sure the key is not already in the hashtable.  
  8.        Entry tab[] = table;  
  9.       int hash = hash(key);  
  10.        int index = (hash & 0x7FFFFFFF) % tab.length;  
  11.        for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {  
  12.            if ((e.hash == hash) && e.key.equals(key)) {  
  13.                V old = e.value;  
  14.                e.value = value;  
  15.                return old;  
  16.            }  
  17.        }  
  18.   
  19.        modCount++;  
  20.        if (count >= threshold) {  
  21.            // Rehash the table if the threshold is exceeded  
  22.            rehash();  
  23.   
  24.            tab = table;  
  25.            hash = hash(key);  
  26.            index = (hash & 0x7FFFFFFF) % tab.length;  
  27.        }  
  28.   
  29.        // Creates the new entry.  
  30.        Entry<K,V> e = tab[index];  
  31.        tab[index] = new Entry<>(hash, key, value, e);  
  32.        count++;  
  33.        return null;  
  34.    }  

源碼中判斷了null value的情況,null value就拋出空指針異常異常

但是我們並沒有看到判斷null key然後拋出異常的語句,那麼繼續看看hash方法的源碼就明白了:

[java] view plain copy
  1. private int hash(Object k) {  
  2.         // hashSeed will be zero if alternative hashing is disabled.  
  3.         return hashSeed ^ k.hashCode();  
  4.     }  

k.hashCode(),當k出入爲null key 就會報錯 空指針異常。

下面是ConcurrentHashMap的源碼:

[java] view plain copy
  1. public V put(K key, V value) {  
  2.         Segment<K,V> s;  
  3.       if (value == null)  
  4.             throw new NullPointerException();  
  5.       int hash = hash(key);  
  6.         int j = (hash >>> segmentShift) & segmentMask;  
  7.         if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck  
  8.              (segments, (j << SSHIFT) + SBASE)) == null//  in ensureSegment  
  9.             s = ensureSegment(j);  
  10.         return s.put(key, hash, value, false);  
  11.     }  

null value和null key 會報錯的問題和HashTable原因是一樣的,hash方法:

[java] view plain copy
  1. private int hash(Object k) {  
  2.        int h = hashSeed;  
  3.   
  4.        if ((0 != h) && (k instanceof String)) {  
  5.            return sun.misc.Hashing.stringHash32((String) k);  
  6.        }  
  7.   
  8.        h ^= k.hashCode();  
  9.   
  10.        // Spread bits to regularize both segment and index locations,  
  11.        // using variant of single-word Wang/Jenkins hash.  
  12.        h += (h <<  15) ^ 0xffffcd7d;  
  13.        h ^= (h >>> 10);  
  14.        h += (h <<   3);  
  15.        h ^= (h >>>  6);  
  16.        h += (h <<   2) + (h << 14);  
  17.        return h ^ (h >>> 16);  
  18.    }  
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章