HashMap和Hashtable都實(shí)現(xiàn)了Map接口松蒜,但決定用哪一個(gè)之前先要弄清楚它們之間的分別幢哨。主要的區(qū)別有:線程安全性雄人,同步(synchronization),以及速度矩距。
1.HashMap幾乎可以等價(jià)于Hashtable拗盒,除了HashMap是非synchronized的,并可以接受null(HashMap可以接受為null的鍵值(key)和值(value)锥债,而Hashtable則不行)陡蝇。
2.HashMap是非synchronized,而Hashtable是synchronized哮肚,這意味著Hashtable是線程安全的毅整,多個(gè)線程可以共享一個(gè)Hashtable;而如果沒(méi)有正確的同步的話绽左,多個(gè)線程是不能共享HashMap的。Java 5提供了ConcurrentHashMap艇潭,它是HashTable的替代拼窥,比HashTable的擴(kuò)展性更好。
- Hashtable蹋凝、HashMap都使用了 Iterator鲁纠。而由于歷史原因,Hashtable還使用了Enumeration的方式 鳍寂。
HashMap的迭代器(Iterator)是fail-fast迭代器改含,而Hashtable的enumerator迭代器不是fail-fast的。所以當(dāng)有其它線程改變了HashMap的結(jié)構(gòu)(增加或者移除元素)迄汛,將會(huì)拋出"ConcurrentModificationException"捍壤,但迭代器本身的remove()方法移除元素則不會(huì)拋出"ConcurrentModificationException"異常。但這并不是一個(gè)一定發(fā)生的行為鞍爱,要看JVM鹃觉。這條同樣也是Enumeration和Iterator的區(qū)別。
4.由于Hashtable是線程安全的也是synchronized睹逃,所以在單線程環(huán)境下它比HashMap要慢盗扇。如果你不需要同步,只需要單一線程沉填,那么使用HashMap性能要好過(guò)Hashtable疗隶。
5.HashMap不能保證隨著時(shí)間的推移Map中的元素次序是不變的。
- HashMap把Hashtable的contains方法去掉了翼闹,改成containsValue和containsKey斑鼻,因?yàn)閏ontains方法容易讓人引起誤解。
Hashtable則保留了contains橄碾,containsValue和containsKey三個(gè)方法卵沉,其中contains和containsValue功能相同颠锉。
7.hash值不同
哈希值的使用不同,HashTable直接使用對(duì)象的hashCode史汗。而HashMap重新計(jì)算hash值琼掠。
hashCode是jdk根據(jù)對(duì)象的地址或者字符串或者數(shù)字算出來(lái)的int類(lèi)型的數(shù)值。
Hashtable計(jì)算hash值停撞,直接用key的hashCode()瓷蛙,而HashMap重新計(jì)算了key的hash值,Hashtable在求hash值對(duì)應(yīng)的位置索引時(shí)戈毒,用取模運(yùn)算艰猬,而HashMap在求位置索引時(shí),則用與運(yùn)算埋市,且這里一般先用hash&0x7FFFFFFF后冠桃,再對(duì)length取模,&0x7FFFFFFF的目的是為了將負(fù)的hash值轉(zhuǎn)化為正值道宅,因?yàn)閔ash值有可能為負(fù)數(shù)食听,而&0x7FFFFFFF后,只有符號(hào)外改變污茵,而后面的位都不變樱报。
8.內(nèi)部實(shí)現(xiàn)使用的數(shù)組初始化和擴(kuò)容方式不同
HashTable在不指定容量的情況下的默認(rèn)容量為11,而HashMap為16泞当,Hashtable不要求底層數(shù)組的容量一定要為2的整數(shù)次冪迹蛤,而HashMap則要求一定為2的整數(shù)次冪。
Hashtable擴(kuò)容時(shí)襟士,將容量變?yōu)樵瓉?lái)的2倍加1盗飒,而HashMap擴(kuò)容時(shí),將容量變?yōu)樵瓉?lái)的2倍陋桂。
Hashtable和HashMap它們兩個(gè)內(nèi)部實(shí)現(xiàn)方式的數(shù)組的初始大小和擴(kuò)容的方式箩兽。HashTable中hash數(shù)組默認(rèn)大小是11,增加的方式是 old*2+1章喉。