HashMap的實現原理--鏈表散列


1.    HashMap概述

   HashMap是基於哈希表的Map接口的非同步實現。此實現提供所有可選的映射操作,並允許使用null值和null鍵。此類不保證映射的順序,特別是它不保證該順序恆久不變。

2.    HashMap的數據結構

   在java編程語言中,最基本的結構就是兩種,一個是數組,另外一個是模擬指針(引用),所有的數據結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“鏈表散列”的數據結構,即數組和鏈表的結合體。這樣的結構結合了鏈表在增刪方面的高效和數組在尋址上的優勢

hashmap結構:哈希表是由數組+鏈表組成的,數組默認長度為16可以自動變長。在構造HashMap的時候也可以指定一個長度),數組里每個元素存儲的是一個鏈表的頭結點。而組成鏈表的結點其實就是hashmap內部定義的一個類:Entity。Entity包含三個元素:key,value和指向下一個Entity的next

3.  HashMap的存取

這些元素是按照什么樣的規則存儲到數組中呢。一般情況是通過hash(key)%(len-1)獲得,也就是元素的key的哈希值對數組長度取模得到。比如上述哈希表中,12%16=12,28%16=12,108%16=12,140%16=12。所以12、28、108以及140都存儲在數組下標為12的位置。

HashMap的存儲--put:

int hash = key.hashCode(); // 這個hashCode方法這里不詳述,只要理解每個key的hash是一個固定的int值
int index = hash %( Entry[].length-1);
table[index] = value;//假定存儲鏈表頭結點的數組名為table

用table[index]表示通過hash值計算出來的、元素需要存儲在數組中的位置。先判斷該位置上有沒有存有Entity,沒有的話就創建一個Entity<k,v>對象,在該位置上插入,插入結束;如果有的話,通過鏈表的遍歷方式去逐個遍歷,通過equals方法將key和已有的key進行比較,看看有沒有已經存在的key,有的話用新的value替換老的value;如果沒有,則在table[index]插入該Entity,把原來在table[index]位置上的Entity賦值給新的 Entity的next,也即,新的Entity插入(put)的位置永遠是在鏈表的最前面,這樣插入結束。 

打個比方, 第一個鍵值對A進來,通過計算其key的hash得到的index=0,記做:table[0] = A。一會后又進來一個鍵值對B,通過計算其index也等於0,現在怎么辦?HashMap會這樣做:B.next = A,table[0] = B,如果又進來C,index也等於0,那么C.next = B,table[0] = C;這樣我們發現index=0的地方其實存取了A,B,C三個鍵值對,他們通過next這個屬性鏈接在一起。

注:null key總是存放在Entry[]數組的第一個元素。

擴展:

按照散列函數的定義,如果兩個對象相同,即obj1.equals(obj2)=true,則它們的hashCode必須相同,但如果兩個對象不同,則它們的hashCode不一定不同。

如果兩個不同對象的hashcode相同,就稱為沖突。沖突會導致操作哈希表的時間開銷增大,所以盡量定義好的hashCode()方法,能加快哈希表的操作。覆蓋了equals方法之后一定要覆蓋hashCode方法,原因很簡單,比如,String a = new String(“abc”);String b = new String(“abc”);如果不覆蓋hashCode的話,那么a和b的hashCode就會不同,把這兩個類當做key存到HashMap中的話就 會出現問題,就會和key的唯一性相矛盾

 HashMap的讀取--get:

先定位到數組元素,再遍歷該元素處的鏈表

public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        //先定位到數組元素,再遍歷該元素處的鏈表
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                return e.value;//顯然,在尋找目標元素的時候,除了對比通過key計算出來的hash值,還會用雙等或equals方法對key本身來進行比較,兩者都為true時才會返回這個元素
        }
        return null;
}

更多詳細資料請參考原文:http://blog.csdn.net/vking_wang/article/details/14166593


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM