HashMap來自互連網的小結

來源:互聯網
上載者:User

       HashMap毋庸置疑,一定是我們這些Java程式員第一大工具 + 生產力,因為其在儲存資料方面,有些“無所不能”哈,而且效率與效能都合我們的意。也是因為這個HashMap在應用程式中應用過多,所以網上出現了針對HashMap的各種剖析,呵呵,鄙人也看過其源碼!瞭解過其具體的實現,所以此時有意來總結一下在網路上的一些對HashMap的各種解析。

HashMap中的Hash演算法
      HashMap使用了散列表,而散列表中要關注的問題是,如何儘可能地減少散列值的衝突,通常有兩種方法,鏈表法和開放地址法。(嗯!資料結構的書上會有更詳盡的解釋)
【鏈表法】將相同hash值的對象組織成為一個鏈表放在hash值對應的槽位;
【開放地址法】通過一個探索演算法,當某個槽位已經被佔據的情況下繼續尋找下一個可以被使用的槽位。
【負載因子和容量】:在JDK中,一個HashMap的實際容量就為 【因子】*【容量】,
   JDK提供的預設值為:16*   0.75=12;
【負載因子】,負載因子a = 散列表的實際元素數目(n)/散列表的容量(m)
  在此,負載因子衡量的是一個散列表的空間使用程度,負載因子越大表示散列表的裝填程度越高,反之越少。
  在JDK中,HashMap採用的是鏈表法的方式,而鏈表為單向鏈表,在刪除過程中要自己維護previous節點
【SourceCode】
for (Entry e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
}
HashMap的資料結構:數組和鏈表的結合體(被稱為“鏈表散列)。如所示:

從這張圖,可得到一些有用資訊,HashMap中get方法的高效率,因為在HashMap中,資料時儲存在數組上,從而就利用了資料的天生優點——可直接通過索引定位元素的位置。當然,在HashMap中的實現中,這個過程並不是像平常那樣直接使用,看看HashMap中get方法實現吧
public V get(Object key) {
        if (key == null)
            return getForNullKey();
        int hash = hash(key.hashCode());
        for (Entry 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;
        }
        return null;
    }
在方法體中,真正定位元素的存放位置也是通過hash值的。
每個元素上的鏈表存放,利用put方法塞元素時,先根據key的hash值得到這個元素在數組上的位置(下標),然後就可以把這個元素放在對應的位置上,若是,這個位置上已有其他元素,那麼就會在同一個位置上將元素以鏈表的形式存放。新的加入放在鏈頭,最先加入的放在鏈尾。HashMap 採用一種所謂的“Hash 演算法”來決定每個元素的儲存位置

HashMap中的resize的實現
當hashmap中的元素越來越多的時候,碰撞的幾率也就越來越高(因為數組的長度是固定的),所以為了提高查詢的效率,就要對hashmap的數組進行擴容。在這個過程中,最消耗效能的關鍵點出現:原數組中的資料必須重新計算在新數組中的位置,並放進去。
這個問題,就要我們在開發過程中,要預知一下HashMap的可能大小,再給它初始化為離這個大小的接近2的整數次冪次方吧!但,這個並不是最完美的解決之道。看某位仁兄的:
比如說,我們有1000個元素new HashMap(1000), 但是理論上來講new HashMap( 1024)更合適,不過,即使是1000,hashmap也自動會將其設定為1024。 但是new HashMap(1024)還不是更合適的,因為0.75*1000 1000, 我們必須這樣new HashMap(2048)才最合適,既考慮了&的問題,也避免了resize的問題。

HashMap的有效使用
如果你想有效使用HashMap,你就必須重寫在其的HashCode()!
覆蓋hashCode方法,使相同內容的對象來說它們的hashcode也就相同了(這樣就能迅速的定位某個元素的位置)
覆蓋equals方法,為了在HashMap中判斷兩個key是否相等時使結果有意義。
在改寫equals方法的時候,需要滿足以下三點:
(1) 自反性:就是說a.equals(a)必須為true。
(2) 對稱性:就是說a.equals(b)=true的話,b.equals(a)也必須為true。
(3) 傳遞性:就是說a.equals(b)=true,並且b.equals(c)=true的話,a.equals(c)也必須為true。

兩條重寫建議牢記的原則:
"不為一原則",不必對每個不同的對象都產生一個唯一的hashcode,只要你的HashCode方法使get()能夠得到put()放進去的內容就可以了。
"分散原則",產生hashcode的演算法盡量使hashcode的值分散一些,不要很多hashcode都集中在一個範圍內,這樣有利於提高HashMap的效能。

【參考的原文章出處,非常感謝大夥們的好文】
http://www.javaeye.com/topic/368087
http://www.javaeye.com/topic/539465

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.