HashMap、LinkedHashMap、HashTable、HashSet筆記

Richal發表於2018-09-19

        HashMap底層使用的是陣列+單連結串列的結構,HashMap中存放的鍵值對(key-value)並且會把他們儲存在Map.Entry中,其中Map.Entry中儲存的是key的hashcode、value值以及下一個Entry物件的引用next。HashMap實現了Map介面其中最常用的方法就是put(K key,V value)get(Object key)方法,其中put方法的原理是檢查key值是否為null,如果為null則將其放入陣列的index為0位置。如果當前key不為0,則對該key值取hashCode,並對改hashCode進行位運算,這樣做的原因是為了避免雜湊碰撞。最後將獲取的值hash對陣列長度取餘數,但是考慮到位位運算的高效性,這裡對獲取的值hash與陣列的長度-1進行&位運算(例如陣列的長度是8,那麼陣列長度-1為7,二進位制九尾0111)這樣保留的是低位的值。獲取到需要插入的值在陣列中的index後,如果陣列該位置處有值並且該位置的Entry的hash值與被插入的值相同,與此同時key值相同(“==”或者equals相同)那麼該位置的value直接替換為將要插入的value值。假如index對應的位置為null或者index對應的位置的Entry不滿足hash值相同並且key值相同(“==”或者equals相同)那麼直接將被插入的值放入到陣列中index位置處,如果該位置有Entry物件,那麼作為被插入Entry的next節點向後移動。

get方法也是根據key的hashcode進行位運算然後獲取到index,然後遍歷該位置的陣列和連結串列值,如果存在Entry的hashcode和該物件的key相同並且與該key相等(“==”或者equals相同),那麼返回該值,否則返回null。HashMap允許鍵值對key-value為null。

       HashTable和HashMap實現了Map介面,基於陣列+單連結串列的結構並且儲存的也是鍵值對,其中比較重要的方法也是Map介面中的put方法和get方法。其中HashTable的put方法與HashMap的相同只是HashMap中如果value為null的話就會丟擲異常,當key不為null的時候剩餘的判斷方式與HashMap相同。如果存在hashcode相同並且key值相同(“==”或者equals相同)的情況那麼直接替換value值。否則index處新增新的Entry物件並且原有值作為被插入物件的next。與HashMap相比,HashTable不允許鍵值對key-value為null,因為只要有一個為null就會丟擲異常,並且HashTable是執行緒安全的,檢視起public方法可以發現都有synchronize的修飾。

       基於以上的理解可以得知HashMap中存入資料是無序的也就是說通過EntrySet的iterator方式列印出的HashMap中的值和put進去的值的順序不一致。而LinkedHashMap可以做到輸入和輸出的順序相同。LinkedHashMap繼承了HashMap並實現了Map介面所以其也有put和get方法,並且LinkedHashMap的資料結構也是陣列+連結串列的資料結構,但是LinkeHashMap維護著一個執行於所有條目的雙重連結列表,此連結列表定義了迭代順序,該迭代順序可以是順序插入或者訪問順序,預設是按順序插入排序,如果指定訪問順序後,呼叫get方法後會將這次訪問的元素移至雙重連線列表的尾部,不斷的訪問可以形成按訪問順序排列的連結串列。LinkedHashMap允許存入key-value均為null,並且鍵值對也是用Map.Entry來封裝,不過增加了兩個變數分別是Entry<K,V>before,after表該Entry在雙連結串列中的前一個節點和後一個節點。

        LinkedHashMap的put方法和HashMap相同,更具key的hashcode計算出鍵值對在陣列中的index,如果遇到index位置有值並且hashcode和被插入的值相同並且key相同(“==”或者equals相同)那麼直接替換value值。如果index的值不滿足以上條件那麼在相應的位置插入新值,並且雙連結串列中將該值放入尾部,並處理該Entry的after和before的指向。如果該值在雙連結串列中已經存在那麼雙連結串列中remove掉之前的值,將該值加到雙連結串列的尾部。如果想按照訪問順序輸入LinkedHashMap中的值,那麼在構造該物件的時候accessOrder出入true,在進行get方法後,執行上述將Entry物件放入雙連結串列的尾部。如果該值設定為false的話則不執行插入雙連結串列的尾部的邏輯。

        HashSet的特點是不允許存入相同的值,其原因是HashSet的底層是一個HashMap,並且HashSet中存入的值是作為HashMap的vaule值,而key是Object物件,所以存入相同的key的時候顯示是一樣的。





相關文章