您的位置:首页 > 编程语言 > Java开发

JDK1.8 --- HashTable和HashMap的区别

2018-08-02 12:49 274 查看

HashTable从实现角度和HashMap大致相同。
不同的有以下几点:

HashTable不允许key和value为null,HashMap允许key和value为null。

/**
* Maps the specified <code>key</code> to the specified
* <code>value</code> in this hashtable. Neither the key nor the
* value can be <code>null</code>. <p>
*
* The value can be retrieved by calling the <code>get</code> method
* with a key that is equal to the original key.
*
* @param      key     the hashtable key
* @param      value   the value
* @return     the previous value of the specified key in this hashtable,
*             or <code>null</code> if it did not have one
* @exception  NullPointerException  if the key or value is
*               <code>null</code>
* @see     Object#equals(Object)
* @see     #get(Object)
*/
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 = key.hashCode();
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;
}

如果value == null 直接抛出空指针异常;
int hash = key.hashCode(); 调用key的hashCode()方法,所以key也不允许为null。

Hashtable是线程安全的,HashMap是线程不安全的。

        因为方法上加了同步synchronized。

Hashtable的初始容量与HashMap不同。

/**
* Constructs a new, empty hashtable with a default initial capacity (11)
* and load factor (0.75).
*/
public Hashtable() {
this(11, 0.75f);
}

        Hashtable的初始容量为11,HashMap的初始容量是16。

Hashtable计算和定位索引的方式和HashMap不同

        Hashtable在定位索引的时候使用key自己的hashCode方法。没有像HashMap一样去做扰动,得到hash值之后与int最大值(0x7FFFFFFF),然后用结果对容量求余
        HashMap在定位索引的时候使用自己实现的hash方法,先求key的hashCode然后高低位做异或扰动,然后与容量做运算。

Hashtable的扩容方式和HashMap不同

/**
1. Increases the capacity of and internally reorganizes this
2. hashtable, in order to accommodate and access its entries more
3. efficiently.  This method is called automatically when the
4. number of keys in the hashtable exceeds this hashtable's capacity
5. and load factor.
*/
@SuppressWarnings("unchecked")
protected void rehash() {
int oldCapacity = table.length;
Entry<?,?>[] oldMap = table;

// overflow-conscious code
int newCapacity = (oldCapacity << 1) + 1;
if (newCapacity - MAX_ARRAY_SIZE > 0) {
if (oldCapacity == MAX_ARRAY_SIZE)
// Keep running with MAX_ARRAY_SIZE buckets
return;
newCapacity = MAX_ARRAY_SIZE;
}
Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];

modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
table = newMap;

for (int i = oldCapacity ; i-- > 0 ;) {
for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
Entry<K,V> e = old;
old = old.next;

int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = (Entry<K,V>)newMap[index];
newMap[index] = e;
}
}
}
  1. 从上面代码可以看出Hashtable扩容之后的容量是原容量的两倍加1。HashMap扩容之后的容量是原容量的两倍。
    这个区别的原因,需要从他们的初始容量说起:HashMap的容量要求必须为2的幂次方,是因为定位索引的方式,2的幂次方的容量能够是的索引值平均分布。。所以在扩容是每次都以两倍的方式。
    而Hashtable定位是通过求余的方式定位,那对什么数求余能最大程度的均匀分布呢?答案是素数(质数)[参考:]https://blog.csdn.net/majinggogogo/article/details/80260539],所以Hashtable在扩容的时候也必须保证扩容之后的数也为素数,所以就在乘以2的前提下再加了1。
    但是,hashtable并没有强制保证容量一定是是质数,因为可以通过初始化或者,putAll的方式调整容量,这可能是HashTable已经不被sun公司推荐使用了。

  2. 扩容方式:hashtable实现比较简单,只是简单的对元素头节点做再次hash,重新分布,不像HashMap会对之后的节点做再次分布,所以对于Hashtable而言扩容之后不会改善hash表的冲突状况。

HashTable的数据结构和HashMap稍有不同

        前面博客提到,HashMap在链表冲突元素达到8个以上时会转化为红黑树,这个是为了查找速度考虑,Hashtable没有这样的策略。

HashMap继承了AbstractMap,HashTable继承Dictionary抽象类,两者均实现Map接口。< 1d810 /h2>

总结:HashMap不能在并发的环境使用,而HashTable不推荐在并发的环境使用,因为Hashtable锁的粒度太大,在并发环境推荐使用 ConcurrentHashMap。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: