HashMap与HashTable的区别
1.HashTable继承自Dictionary抽象类,HashMap实现Map接口
2.HashTable的方法都是synchronized的,HashMap不是
3.HashMap允许键或值为null,HashTable不可以
4.HashTable保留了Contains方法,HashMap没有
5.内部实现使用的数组初始化和扩容方式不同。HasTable默认容量为11,HashMap为16。Hashtable扩容时,将容量变为原来的2倍加1,而HashMap扩容时,将容量变为原来的2倍。
为什么HashMap允许键或值为null,HashTable不可以?
Hashtable put()方法源码:
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; }
Hashtable hash()方法源码:
private int hash(Object k) { // hashSeed will be zero if alternative hashing is disabled. return hashSeed ^ k.hashCode(); }
if (value == null) { throw new NullPointerException(); }
hashSeed ^ k.hashCode();
可见,当key或value为null时,再进行put时会报出空指针异常。
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; }
可见HashMap的对代码进行了修改,支持插入null的键和值。
参考链接:HashMap与HashTable的区别