hashMap的具體實現

HashMap是Java中的一個重要的數據結構!html

與HashMap更重要的一個數據結構是HashTable,其中最重要的區別是HashTable傳說中是線程安全的(之因此說他是傳說是由於我並無去理解爲何,這是個人錯,沒有理解就搬上了講臺!)java

HashMap的內部結構很簡單,以下(圖片來自importnews,專屬java的一個實時blog.本文也必定程度上參考了importnews,之全部沒有直接轉載是由於我以爲,有些東西,你只是看到了,他並不屬於你!而我要作的,就是消化它,達到能夠有本身看法的地方,原文連接地址:http://www.importnew.com/10620.html)數組

在HashMap內部,實現存貯key-value鍵值對的是一個Entity的內部類,安全

static class Entry implements Map.Entry
{
        final K key;
        V value;
        Entry next;
        final int hash;
        ...//More code goes here
}   `

這個類能夠構成一個鏈表,在key中的hashCode相同時,會構成一個鏈表,數據結構

這個類在HashMap中構成了一個table數組,全部的鍵值對就保留在這個鍵值對數組之中,這個數據默認的長度是16,當數據超過這個大小以後,會自動的真正增加,可是若是數據剛恰好處於增加的上邊緣,也就是>=,會形成數據內存大浪費,一些文章推薦咱們在使用一些集合類的時候要指定好它的大小,避免形成過大的內存泄漏函數

從咱們日常使用的HashMap中咱們能夠得出,操縱HashMap只是經過put和get方法post

1.瞭解put方法this

 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;
 }
  1. 對key作null檢查。若是key是null,會被存儲到table[0],由於null的hash值老是0。spa

  2. key的hashcode()方法會被調用,而後計算hash值。hash值用來找到存儲Entry對象的數組的索引。有時候hash函數可能寫的 很很差,因此JDK的設計者添加了另外一個叫作hash()的方法,它接收剛纔計算的hash值做爲參數。若是你想了解更多關於hash()函數的東西,可 以參考:hashmap中的hash和indexFor方法線程

  3. indexFor(hash,table.length)用來計算在table數組中存儲Entry對象的精確的索引。

  4. 在咱們的例子中已經看到,若是兩個key(這裏指的是兩個不一樣key值)有相同的hash值(也叫衝突),他們會以鏈表的形式來存儲。因此,這裏咱們就迭代鏈表。

  • 若是在剛纔計算出來的索引位置沒有元素,直接把Entry對象放在那個索引上。
  • 若是索引上有元素,而後會進行迭代,一直到Entry->next是null。當前的Entry對象變成鏈表的下一個節點。
  • 若是咱們再次放入一樣的key會怎樣呢?邏輯上,它應該替換老的value。事實上,它確實是這麼作的。在迭代的過程當中,會調用equals() 方法來檢查key的相等性(key.equals(k)),若是這個方法返回true,它就會用當前Entry的value來替換以前的value。

2.瞭解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;
  }
  return null;
 }

你傳遞一個key從hashmap總獲取value的時候:

  1. 對key進行null檢查。若是key是null,table[0]這個位置的元素將被返回。

  2. key的hashcode()方法被調用,而後計算hash值。

  3. indexFor(hash,table.length)用來計算要獲取的Entry對象在table數組中的精確的位置,使用剛纔計算的hash值。

  4. 在獲取了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的惟一性。
  • value對象的equals()和hashcode()方法根本一點用也沒有。
相關文章
相關標籤/搜索