HashTable是更早于HashMap出現的敞斋,兩者有一些類似,比如思想啊恼除,比如現在都默認用了拉鏈法等等踪旷,但是更多的應該關注他們之間的區(qū)別,區(qū)別有哪些呢豁辉?
一令野、HashMap的key和value都可以是null,但是HashTable的key和value都不能是null(編譯能通過徽级,但是運行會報錯)
HashMap的key如果是null的話气破,它們會被存放在table[0]的位置,也就是hash鏈表的首位灰追,如果value是null,那很容易理解的狗超。來看看源碼:
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
如果key==null的時候弹澎,返回的hash值是0,如果key不為null的話努咐,返回的是key的hash值和該值奇偶性的與值苦蒿,而hashtable在這里是這樣的:
if (value == null) {
throw new NullPointerException();
}
可以自己去試試編譯會不會報錯哦。
二渗稍、HashTable是線程安全的佩迟,HashMap是線程不安全的
HashTable是線程安全的,利用了synchronized方法竿屹,HashMap的报强,當然就沒用synchronized,所以現在有個CurrenthashMap是線程安全的拱燃,道理都懂秉溉,還是要來看看源碼的,CurrenthashMap的源碼有意思:
public V put(K key, V value) {
return putVal(key, value, false);
}
首先碗誉,他是不允許key和value為null的召嘶,然后它是怎么實現線程安全的:
synchronized (f) {...}
它在每個對鍵值對操作的方法中都加上了synchronized,這個f是啥哮缺?
Node<K,V> f;
f就是鍵值對
三弄跌、HashTable的hash方法用的是取余數法,HashMap用的是hashcode()
hashMap的源碼:
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
hashtable的源碼:
// Makes sure the key is not already in the hashtable.
Entry<?,?> tab[] = table;
int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;
可以看出hashtable用的是取余數尝苇,取余數我們知道比位運算要慢很多铛只,大概是十倍的樣子埠胖,因此HashMap在效率上是一種改進(更不用說synchronized對效率的影響)。
因此currenthashMap是繼承了hashMap的優(yōu)點和hashtable優(yōu)點的格仲,既是線程安全的押袍,又在hash的時候采用位運算提高了效率,更多的currenthashMap在加鎖的時候是將一個大的segment切分成小的segment來實現所以并發(fā)效率更高凯肋。
四谊惭、HashMap的默認容量是16,HashTable的是11侮东,裝載因子都是0.75圈盔,擴容是HashMap是2n,HashTable是2n+1
裝載銀因子沒啥好說的悄雅,是一個百分比的閾值驱敲,但是這個擴容很有說法,為啥一個是2n一個是2n+1呢宽闲?因為hashMap用的位運算众眨,它的長度一直能保持是偶數的,hash值和偶數做與運算容诬,那么有可能是偶數也能是奇數娩梨,但是如果它擴容用2n+1,那么hash值和一個奇數做與運算那只能是奇數览徒,是不是會浪費掉偶數的一半的空間狈定?