1.线程的安全性不同
HashMap线程不安全(在多线程并发会造成死锁的问题)但是他的效率比HashTable高,大部分都是单线程操作。
HashTable线程安全(它的每一个地方都加了锁,适用于多线程并发的环境)。
public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function)
2.继承的父类不同
HashMap是继承AbstractMap类都实现map,cloneable serializable接口
HashTable是继承Dictionary类都实现了map,cloneable serializable接口
3.初始容量大小和每次扩容的大小不同
HashTable:
public Hashtable() {
this(11, 0.75f);
}
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;
// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1; //这里是扩容后的值为2n+1
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
HashMap:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始值 16
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
} //newCap = oldCap << 1这里实现扩容扩大两倍
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold
}
HashTable默认的初始大小为11每次扩容为2n+1
HashMap默认的初始化大小是16每次扩容为两倍
4.key和value是否允许为null值
HashTable:
public synchronized V put(K key, V value) {
// Make sure the value is not null
if (value == null) {
throw new NullPointerException();
//这里value为空的话直接抛出NullPointerException异常
}
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode(); //key为空的话也会抛出NullPointerException异常
int index = (hash & 0x7FFFFFFF) % tab.length;
@SuppressWarnings("unchecked")
Entry<K,V> entry = (Entry<K,V>)tab[index];
for(; entry != null ; entry = entry.next) {
if ((entry.hash == hash) && entry.key.equals(key)) {
V old = entry.value;
entry.value = value;
return old;
}
}
addEntry(hash, key, value, index);
return null;
}
HashMap:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
//这里当key为null时会给他赋值为0
}
HashTable中,key和value都不能为null。
HashMap中,可以允许key和value为空的且存储在数组索引为0处。
5.计算hash值的方式不同
(1)HashMap有个hash方法重新计算了key的hash值,因为hash冲突变高,所以通过一种方法重算hash值的方法:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
这里计算hash值,先调用hashCode方法计算出来一个hash值,再将hash与右移16位后相异或,从而得到新的hash值
(2)Hashtable通过计算key的hashCode()**来得到hash值就为最终hash值:
int hash = key.hashCode()