青菜貓(孫宇博客),青菜貓(孫宇博客),青菜貓(孫宇博客)http://www.javasdc.cn/
          posts - 29,  comments - 63,  trackbacks - 0

          HashMap 是通過(guò)key_value當(dāng)成一個(gè)整體進(jìn)行處理,通過(guò)key的hashCoder反回一個(gè)int數(shù),然后還會(huì)調(diào)用一個(gè)hash方法。來(lái)確定存儲(chǔ)位置。
          HashMap 存儲(chǔ)java對(duì)像,其實(shí)并沒(méi)有真正將 Java 對(duì)象放入 Set 集合中,而是多個(gè)引用變量所組成的集合,這些引用變量指向?qū)嶋H的 Java 對(duì)象。
          HashMap 存儲(chǔ).以如下代碼為例:
          HashMap<String,String> ma = new HashMap<String,String>();
                  ma.put("a", "aaa");
                  ma.put("b", "bbb");
          HashMap 采用一種所謂的“Hash 算法”來(lái)決定每個(gè)元素的存儲(chǔ)位置。
          在上面代碼中系統(tǒng)會(huì)調(diào)用a的hashCode方法來(lái)確定來(lái)決定該元素的存儲(chǔ)位置。以下是部分源碼
          public V put(K key, V value) {
                  if (key == null)
                      return putForNullKey(value);
                  int hash = hash(key.hashCode());
                  int i = indexFor(hash, table.length);
                  for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                      Object k;
                      if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                          V oldValue = e.value;
                          e.value = value;
                          e.recordAccess(this);
                          return oldValue;
                      }
                  }

                  modCount++;
                  addEntry(hash, key, value, i);
                  return null;
           }

          hash方法對(duì)應(yīng)在下面
           static int hash(int h) {
                  // This function ensures that hashCodes that differ only by
                  // constant multiples at each bit position have a bounded
                  // number of collisions (approximately 8 at default load factor).
                  h ^= (h >>> 20) ^ (h >>> 12);
                  return h ^ (h >>> 7) ^ (h >>> 4);
           }
          大家可以看下上面的Entry,我理解成其實(shí)就是一個(gè)key_value對(duì)。然后通過(guò)hash(key.hashCode())這樣確定位置。系統(tǒng)這樣才能存儲(chǔ)在那里。
          關(guān)鍵是int i = indexFor(hash, table.length);我理解是這個(gè)對(duì)找到相對(duì)應(yīng)的索引塊。加快速度。包括get的時(shí)候也會(huì)調(diào)用這個(gè)方法,確實(shí)索引塊的位置.
          來(lái)看看具體算法
           static int indexFor(int h, int length) {
                  return h & (length-1);
           }
          h是hash的一個(gè)值,length中這個(gè)table的長(zhǎng)度。假設(shè) h=5,length=16, 那么 h & length - 1 將得到 5,這個(gè)length為什么我會(huì)假設(shè)是16,大家可以看看源碼
          也就知道static final int DEFAULT_INITIAL_CAPACITY = 16; 初始化的時(shí)候就是16。這樣目的在于計(jì)算得到的索引值總是位于 table 數(shù)組的索引之內(nèi)
          根據(jù)上面 put 方法的源代碼可以看出,當(dāng)程序試圖將一個(gè) key-value 對(duì)放入 HashMap 中時(shí),
          程序首先根據(jù)該 key 的 hashCode() 返回值決定該 Entry 的存儲(chǔ)位置:如果兩個(gè) Entry 的 key 的 hashCode() 返回值相同,
          那它們的存儲(chǔ)位置相同。如果這兩個(gè) Entry 的 key 通過(guò) equals 比較返回 true,
          新添加 Entry 的 value 將覆蓋集合中原有 Entry 的 value,但 key 不會(huì)覆蓋。如果這兩個(gè) Entry 的 key 通過(guò) equals 比較返回 false
          ,新添加的 Entry 將與集合中原有 Entry 形成 Entry 鏈,而且新添加的 Entry 位于 Entry 鏈的頭部——具體說(shuō)明繼續(xù)看 addEntry() 方法的說(shuō)明。

          void addEntry(int hash, K key, V value, int bucketIndex) {
              Entry<K,V> e = table[bucketIndex];
                  table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
                  if (size++ >= threshold)
                      resize(2 * table.length);
              }
          大家看看這里就知道了, 就是把添加的 Entry 對(duì)象放入 table 數(shù)組的 bucketIndex 索引處——如果 bucketIndex 索引處已經(jīng)有了一個(gè) Entry 對(duì)象,那新添加的 Entry 對(duì)象指向原有的 Entry 對(duì)象(產(chǎn)生一個(gè) Entry 鏈),
          如果 bucketIndex 索引處沒(méi)有 Entry 對(duì)象,也會(huì)新放入的 Entry 對(duì)象指向 null,也就是沒(méi)有產(chǎn)生 Entry 鏈。
           如果 Map 中的 key-value 對(duì)的數(shù)量超過(guò)了極限,就會(huì)度擴(kuò)充到 2 倍。
          HashMap的取值
          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;
                  }
                  return null;
              }
          其實(shí)也是先要找到對(duì)應(yīng)的位置,HashMap是用equals判斷當(dāng)前鍵是否和表中的鍵相同。所以在這里要說(shuō)明如果要用自己的類(lèi)做為HashMap的鍵,必須同時(shí)重載wqual()和hashCode()









          posted on 2010-09-01 11:39 青菜貓(孫宇) 閱讀(2236) 評(píng)論(1)  編輯  收藏 所屬分類(lèi): java


          FeedBack:
          # re: HashMap源碼解析
          2010-09-02 09:44 | 瀧洲彼岸-Scelong
          所以在這里要說(shuō)明如果要用自己的類(lèi)做為HashMap的鍵,必須同時(shí)重載wqual()和hashCode()

          樓主,這里的“重載”是不是應(yīng)該為重寫(xiě)或覆蓋呢?  回復(fù)  更多評(píng)論
            
          <2010年9月>
          2930311234
          567891011
          12131415161718
          19202122232425
          262728293012
          3456789

          青菜貓(孫宇)結(jié)交天下朋友,在網(wǎng)上吸取知識(shí)..

          常用鏈接

          留言簿(16)

          隨筆分類(lèi)

          隨筆檔案

          文章分類(lèi)

          搜索

          •  

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          青菜貓(孫宇博客),青菜貓(孫宇博客),青菜貓(孫宇博客)http://www.javasdc.cn/
          主站蜘蛛池模板: 日土县| 莎车县| 枝江市| 岳普湖县| 安阳市| 襄垣县| 永修县| 灵石县| 瓦房店市| 宕昌县| 巴林左旗| 安达市| 南康市| 新巴尔虎左旗| 侯马市| 专栏| 临猗县| 赤城县| 光山县| 峡江县| 高邮市| 安国市| 涞源县| 古蔺县| 宣恩县| 潞城市| 金沙县| 婺源县| 聂拉木县| 建瓯市| 留坝县| 京山县| 富平县| 登封市| 平昌县| 玉田县| 金山区| 嵊泗县| 峡江县| 晋江市| 灵宝市|