HsahMap的工做原理

  只要是學習Java或者是Java程序員,都知道而且用過HaseMap,知道他是用鍵值對來存儲數據而且能夠接受null的鍵和值,今天看到有人提及了HaseMap的工做原理,所以我在這裏把他記錄下來,以便本身在之後忘了的時候閱讀了解。html

  HaseMap的put()與get()方法的工做原理:程序員

  1、Put :

  讓咱們看下put方法的實現:
/**

  * Associates the specified value with the specified key in this map. If the

  * map previously contained a mapping for the key, the old value is

  * replaced.

  *

  * @param key

  *            key with which the specified value is to be associated

  * @param value

  *            value to be associated with the specified key

  * @return the previous value associated with <tt>key</tt>, or <tt>null</tt>

  *         if there was no mapping for <tt>key</tt>. (A <tt>null</tt> return

  *         can also indicate that the map previously associated

  *         <tt>null</tt> with <tt>key</tt>.)

  */

 publicV put(K key, V value) {

  if(key ==null)

   returnputForNullKey(value);

  inthash = hash(key.hashCode());

  inti = 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);

    returnoldValue;

   }

  }

 

  modCount++;

  addEntry(hash, key, value, i);

  returnnull;

 }

如今咱們一步一步來分析上面的代碼。 對key作null檢查。若是key是null,會被存儲到table[0],由於null的hash值老是0。 
key的hashcode()方法會被調用,而後計算hash值。hash值用來找到存儲Entry對象的數組的索引。有時候hash函數可能寫的很
很差,因此JDK的設計者添加了另外一個叫作hash()的方法,它接收剛纔計算的hash值做爲參數。若是你想了解更多關於hash()函
數的東西,能夠參考:hashmap中的hash和indexFor方法indexFor(hash,table.length)用來計算在table數組中存儲Entry對
象的精確的索引。 在咱們的例子中已經看到,若是兩個key有相同的hash值(也叫衝突),他們會以鏈表的形式來存儲。因此,這裏咱們就迭代鏈表。 · 若是在剛纔計算出來的索引位置沒有元素,直接把Entry對象放在那個索引上。 · 若是索引上有元素,而後會進行迭代,一直到Entry->next是null。當前的Entry對象變成鏈表的下一個節點。 · 若是咱們再次放入一樣的key會怎樣呢?邏輯上,它應該替換老的value。事實上,它確實是這麼作的。在迭代的過程當中,會調用equals()方法來檢查key的相等性(key.equals(k)),若是
這個方法返回true,它就會用當前Entry的value來替換以前的value。 Get: 如今咱們來看下get方法的實現:
/**

  * Returns the value to which the specified key is mapped, or {@code null}

  * if this map contains no mapping for the key.

  *

  * <p>

  * More formally, if this map contains a mapping from a key {@code k} to a

  * value {@code v} such that {@code (key==null ? k==null :

  * key.equals(k))}, then this method returns {@code v}; otherwise it returns

  * {@code null}. (There can be at most one such mapping.)

  *

  * </p><p>

  * A return value of {@code null} does not <i>necessarily</i> indicate that

  * the map contains no mapping for the key; it's also possible that the map http://www.heyzc.com/pro/45.html

  * explicitly maps the key to {@code null}. The {@link #containsKey

  * containsKey} operation may be used to distinguish these two cases.

  *

  * @see #put(Object, Object)

  */

 publicV get(Object key) {

  if(key ==null)

   returngetForNullKey();

  inthash = 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)))

    returne.value;

  }

  returnnull;

 }
 

 


當你理解了hashmap的put的工做原理,理解get的工做原理就很是簡單了。當你傳遞一個key從hashmap總獲取value的時候: 對key進行null檢查。若是key是null,table[0]這個位置的元素將被返回。 key的hashcode()方法被調用,而後計算hash值。 indexFor(hash,table.length)用來計算要獲取的Entry對象在table數組中的精確的位置,使用剛纔計算的hash值。 在獲取了table數組的索引以後,會迭代鏈表,調用equals()方法檢查key的相等性,若是equals()方法返回true,get方法返回Entry對象的value,不然,返回null。
要牢記如下關鍵點:

· HashMap有一個叫作Entry的內部類,它用來存儲key-value對。 · 上面的Entry對象是存儲在一個叫作table的Entry數組中。 · table的索引在邏輯上叫作「桶」(bucket),它存儲了鏈表的第一個元素。 · key的hashcode()方法用來找到Entry對象所在的桶。 · 若是兩個key有相同的hash值,他們會被放在table數組的同一個桶裏面。 · key的equals()方法用來確保key的惟一性。 
相關文章
相關標籤/搜索