Hashtable和HashMap
前不久用JAVA寫了一個簡單的雜湊表,但是在和Hashtable、HashMap進行效能測試比較時,發現相差得有點大,於是專門去探究了一下Hashtable和HashMap的一些特性。
一、Hashtable和HashMap的不同
1.繼承物件不同
Hashtable繼承Dictionary類,而HashMap繼承Map類繼承AbstractMap類。
2.雜湊表的初始容量和擴充套件方法不同
Hashtable的預設初始容量是11。而HashMap的預設初始容量是16。並且它的註釋還強調了一句話,“The default initial capacity - MUST be a power of two.”就是這個初始容量的大小必須是2的倍數,這個強調是為了後面用移位操作來取代一些除法操作。因為在計算機中除法時非常耗時間的,而移位操作相對簡單的多。
Hashtable的擴充套件公式為2*n+1,而HashMap的擴充套件公式為2*n。Hashtable的擴充套件方式使得容量大小一直都是奇數,因為只有奇數才有可能是素數,它希望每次擴充套件後的容量都能夠是素數,這樣子就能夠減少雜湊衝突次數。而HashMap則是為了簡化一些計算,把取餘數的除法都變成簡單的位移操作,因此擴充套件後的雜湊表容量都是2的倍數。
3.雜湊碼的計算方法不同——決定新增資料是否可為null
Hashtable的原始碼如下。它的put()方法中明確指出如果value等於null就會丟擲空指標異常的錯誤。但是這裡並沒有說key值不能為null,於是我就嘗試著新增一個key為null,value不為null的值,結果還是丟擲了空指標的錯誤。
既然put函式中沒有指明key必須為null,那就是put()方法裡面呼叫的其他方法有這個限制,初步猜測應該是hashcode()方法,但是這個方法是private型別的,我們在這裡看不到它的具體實現。那麼就只能進行手動測試了。測過結果如下:
果然是hashcode()的問題。null是沒有hashcode的。
我們接著來看一下HashMap。它的put方法中沒有對value進行限制,那麼key呢?既然Object類裡面的Hashcode()不允許為null,如果HashMap直接呼叫這個函式來計算key的雜湊碼,那麼它的key也肯定不能為null。也許正是為了讓key可以為null,他們並沒有直接使用Object自帶的hashcode()方法,而是自己寫了一個hash方法來計算key的雜湊碼,不過其中還是呼叫了hashcode()方法,程式碼如下。如果key==null,那麼它的雜湊碼就為0;如果不為null,再呼叫hashcode()方法,並進行一個異或運算。這樣子HashMap新增的資料key和value都可以為null。
注意:判斷是否含有某個鍵
在HashMap 中,null 可以作為鍵。當get()方法返回null 值時,既可以表示HashMap 中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap 中不能用get()方法來判斷HashMap 中是否存在某個鍵,而應該用containsKey()方法來判斷。
Hashtable 的鍵值都不能為null,所以可以用get()方法來判斷是否含有某個鍵。返回null的時候說明沒有表中這個鍵值對。
4.遍歷方式不同
Hashtable是使用的是Enumeration(列舉),而HashMap使用iterator(迭代器迭代)。
5.是否執行緒安全的
Hashtable是執行緒安全的,它使用了syncronized關鍵字來保證執行緒安全(所謂執行緒安全就是多個執行緒都在使用這個雜湊表時,不會出現資料混亂),而Hashtable的執行緒安全採用的是最簡單粗暴的方法——如果當前已經有一個執行緒在使用這個雜湊表,那麼這個雜湊表就會被鎖住,不允許其他執行緒使用,其他執行緒只能等這個執行緒使用結束後才能使用,這樣一來雖然操作安全,但是也會降低程式的效率。而HashMap不是執行緒安全的。它允許多個執行緒同時操作同一個雜湊表,這樣子效率雖然高,但是雜湊表的結構和資料可能會亂掉。因此多執行緒程式設計優先選擇Hashtable,單執行緒程式設計優先選擇HashMap。
當然還有一種更好的選擇,那就是ConcurrentHashMap,這個繼承自AbstractMap,跟Map很相似。但是它進一步處理HashMap執行緒不安全的問題。它跟Hashtable一樣是執行緒安全的,而相較於Hashtable的整段鎖,它採用的是分段鎖的方法,提高了程式的執行效率。
二、兩者的相同點
1.它們的裝載因子都是0.75。
2.都是採用陣列+連結串列的實現
三、如何提高雜湊表的效能
1.減低雜湊衝突的次數——Hashtable通過令雜湊表容量儘量為素數來降低
2.避免雜湊表過度失衡——採用紅黑樹來平衡雜湊表
3.雜湊碼的計算速度——HashMap採用移位操作來替代除法
小結:分析到這裡我們對Hashtable和HashMap的整體實現和它們之間的區別有了一個大致的理解。當然這裡面還涉及到很多知識,一篇博文肯定是難以講清的,需要我們在JAVA的學習過程中再慢慢去探究。而在這次探究Hashtable和HashMap的過程中,有幾點小感悟在這裡記錄一下。
1.要善於閱讀原始碼——能寫出這些API的都是大佬中的大佬,閱讀原始碼就是一個和大佬交流的過程。
2.emmm,英語要學好——註釋都是英語,有道翻譯啥的都不是那麼靠譜,能夠自己看懂最好
3.看不到的原始碼可以通過樣例測試來探究它的一些內部實現。
相關文章
- C#中Hashtable和HashMap的區別C#HashMap
- 【java】【Map】HashMap、Hashtable、CollectionsJavaHashMap
- java複習之HashMap和Hashtable的區別JavaHashMap
- HashMap、HashTable、ConcurrentHashMap的區別HashMap
- HashMap、LinkedHashMap、HashTable、HashSet筆記HashMap筆記
- 集合類HashMap,HashTable,ConcurrentHashMap區別?HashMap
- HashMap、Hashtable、ConcurrentHashMap的原理與區別HashMap
- HashMap底層實現原理/HashMap與HashTable區別/HashMap與HashSet區別HashMap
- HashMap為何執行緒不安全?HashMap,HashTable,ConcurrentHashMap對比HashMap執行緒
- Hashtable/HashMap與key/value為null的關係HashMapNull
- 10分鐘掌握ConcurrentHashMap 3分鐘清楚和HashMap、Hashtable的區別HashMap
- HashTable、ConcurrentHashMap、TreeMap、HashMap關於鍵值的區別HashMap
- 為什麼hashtable不允許設定Null但是hashmap允許?NullHashMap
- 五分鐘看懂Hashtable原始碼以及與HashMap的區別原始碼HashMap
- 一文讀懂JDK7,8,9的hashmap,hashtable,concJDKHashMap
- Java集合系列(四):HashMap、Hashtable、LinkedHashMap、TreeMap的使用方法及區別JavaHashMap
- Java集合詳解4:一文讀懂HashMap和HashTable的區別以及常見面試題JavaHashMap面試題
- HashSet和HashMapHashMap
- 一文讀懂JDK7,8,9的hashmap,hashtable,concurrenthashmap及他們的區別JDKHashMap
- ConcurrentHashMap 與HashTableHashMap
- 深度解析Hashtable
- 三,TreeMap和HashMap,TreeSet和HashMap的區別以及方法使用上的不同HashMap
- ArrayList和hashMap的遍歷HashMap
- C++ STL -- HashTableC++
- 資料結構和演算法-雜湊表 (HashTable)資料結構演算法
- hashMap 中key和value互換HashMap
- TreeMap和HashMap的元素比較HashMap
- 一文讀懂JDK1.7,JDK1.8,JDK1.9的hashmap,hashtable,concurrenthashmap及他們的區別JDKHashMap
- Java HashMap 和 HashSet 的高效使用技巧JavaHashMap
- hashmap和concurrenthashmap原始碼分析(1.7/1.8)HashMap原始碼
- HashTable實現程式碼分享
- HashTable與ConcurrentHashMap的區別HashMap
- HashMap原理(一) 概念和底層架構HashMap架構
- HashMap原始碼解析和設計解讀HashMap原始碼
- <<快速入手Rust>>14.HashMap和其他集合RustHashMap
- Java HashMap和Go map原始碼對比JavaHashMapGo原始碼
- HashMap jdk1.7和1.8原始碼剖析HashMapJDK原始碼
- 資料結構HashMap(Android SparseArray 和ArrayMap)資料結構HashMapAndroid