<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    java.util.HashMap源碼要點淺析

    Posted on 2009-04-15 12:33 dennis 閱讀(4385) 評論(0)  編輯  收藏 所屬分類: java數據結構與算法源碼解讀
    1、散列表要解決的一個問題就是散列值的沖突問題,通常是兩種方法:鏈表法和開放地址法。鏈表法就是將相同hash值的對象組織成一個鏈表放在hash值對應的槽位;開放地址法是通過一個探測算法,當某個槽位已經被占據的情況下繼續查找下一個可以使用的槽位。java.util.HashMap采用的鏈表法的方式,鏈表是單向鏈表,因此在刪除過程中要自己維持prev節點,我想不采用雙向鏈表是從節省空間考慮。一個典型的查找過程:
    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 != null && key.equals(k))))
                    
    return e;
     }
       HashMap采用鏈表法而不是開放地址法,猜想可能的原因是從實用角度出發,對空間和時間效率做出的折中選擇。采用開放地址法,無論是線性探測或者二次探測都可能造成群集現象,而雙重散列會要求散列表的裝填程度比較低的情況下會有比較好的查找效率,容易造成空間的浪費。

    2、什么是負載因子?負載因子a定義為
         a=散列表的實際元素數目(n)/ 散列表的容量(m)

    負載因子衡量的是一個散列表的空間的使用程度,負載因子越大表示散列表的裝填程度越高,反之愈小。對于使用鏈表法的散列表來說,查找一個元素的平均時間是 O(1+a),因此如果負載因子越大,對空間的利用更充分,然而后果是查找效率的降低;如果負載因子太小,那么散列表的數據將過于稀疏,對空間造成嚴重浪費。

    回到HashMap的實現,HashMap中的loadFactor其實定義的就是該map對象允許的最大的負載因子,如果超過這個系數將重新resize。這個是通過threshold字段來判斷,看threshold的計算:
    threshold = (int)(capacity * loadFactor);

    結合上面的負載因子的定義公式可知,threshold就是在此loadFactor和capacity對應下允許的最大元素數目,超過這個數目就重新resize,以降低實際的負載因子。默認的的負載因子0.75是對空間和時間效率的一個平衡選擇。注意到的一點是resize的規模是現有 capacity的兩倍:
      if (size++ >= threshold)
                resize(
    2 * table.length);
     
    3、可能你也注意到了,java.util.HashMap對key的hash值多做了一步處理,而不是直接使用hashCode:

    static int hash(int h) {
            h 
    ^= (h >>> 20^ (h >>> 12);
            
    return h ^ (h >>> 7^ (h >>> 4);
      }

    這個處理的原因在于HashMap的容量總是采用2的p次冪,而取index(槽位)的方法是
    static int indexFor(int h, int length) {
            
    return h & (length-1);
     }

    這一運算等價于對length取模,也就是
           h % 2^p
    返回的將是h的p個最低位組成的數字,我們假設hash輸入是符合簡單一致散列,然而這一假設并不能推論出hash的p個最低位也會符合簡單一致散列,也許h的這p個最低位相同的幾率很大,那么沖突的幾率就非常大了。優秀的散列函數應該需要考慮所有的位。

    因此為了防止這些“壞”的散列函數造成效率的降低,HashMap預先對hash值做了處理以考慮到所有的位,根據注釋也可以知道。這個處理我看不懂,留待高人解釋,也許來自于某本算法書也不一定。

    4、我們知道java.util.HashMap不是線程安全的,因此如果在使用迭代器的過程中有其他線程修改了map,那么將拋出ConcurrentModificationException,這就是所謂fail-fast策略(速錯),這一策略在源碼中的實現是通過 modCount域,modCount顧名思義就是修改次數,對HashMap內容的修改都將增加這個值,那么在迭代器初始化過程中會將這個值賦給迭代器的expectedModCount,

     HashIterator() {
                expectedModCount 
    = modCount;
                
    if (size > 0) { // advance to first entry
                    Entry[] t = table;
                    
    while (index < t.length && (next = t[index++]) == null)
                        ;
                }
            }

    在迭代過程中,判斷modCount跟expectedModCount是否相等,如果不相等就表示已經有其他線程修改了map

      
    final Entry<K,V> nextEntry() {
                
    if (modCount != expectedModCount)
                    
    throw new ConcurrentModificationException();
     注意到modCount聲明為volatile,保證線程之間修改的可見性。
     




    主站蜘蛛池模板: 成年女人午夜毛片免费视频| 91免费国产自产地址入| 国产日产成人免费视频在线观看| 亚洲一区免费在线观看| 丁香花免费完整高清观看| 33333在线亚洲| 免费无码AV片在线观看软件| 亚洲中文字幕久久无码| 免费毛片在线视频| 久久人午夜亚洲精品无码区 | 一级女性全黄生活片免费看| 免费播放春色aⅴ视频| 亚洲日韩中文字幕一区| 日韩免费毛片视频| 免费看黄网站在线看| 自拍偷自拍亚洲精品情侣| 久久久国产精品无码免费专区| 中文字幕亚洲综合久久2| 91麻豆最新在线人成免费观看| 亚洲AV无码成人专区| 日本黄色免费观看| 国产乱子伦精品免费视频| 亚洲AV日韩精品久久久久久久| 4虎1515hh永久免费| 7777久久亚洲中文字幕| www国产亚洲精品久久久日本| 999zyz**站免费毛片| 久久亚洲熟女cc98cm| 成视频年人黄网站免费视频| 狼人大香伊蕉国产WWW亚洲| 亚洲国产精品成人精品无码区 | 免费无码又爽又刺激聊天APP| 色欲aⅴ亚洲情无码AV| 精品国产亚洲一区二区三区 | 亚洲精品国产成人中文| 免费无码又爽又刺激高潮的视频| 一区二区三区在线免费观看视频 | 亚洲卡一卡2卡三卡4麻豆| 一本色道久久88亚洲综合| 亚洲视频免费在线观看| 337P日本欧洲亚洲大胆精品|