程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 深刻懂得Java中的HashMap的完成機制

深刻懂得Java中的HashMap的完成機制

編輯:關於JAVA

深刻懂得Java中的HashMap的完成機制。本站提示廣大學習愛好者:(深刻懂得Java中的HashMap的完成機制)文章只能為提供參考,不一定能成為您想要的結果。以下是深刻懂得Java中的HashMap的完成機制正文


假如任何人讓我描寫一下HashMap的任務機制的話,我就簡略的答復:“基於Hash的規矩”。這句話異常簡略,然則要懂得這句話之前,起首我們得懂得甚麼是哈希,不是麼?

甚麼是哈希
哈希簡略的說就是對變量/對象的屬性運用某種算法後獲得的一個獨一的串,用這個串來肯定變量/對象的獨一性。一個准確的哈希函數必需遵照這個原則。

當哈希函數運用在雷同的對象或許equal的對象的時刻,每次履行都應當前往雷同的值。換句話說,兩個相等的對象應當有雷同的hashcode。

注:一切Java對象都從Object類繼續了一個默許的hashCode()辦法。這個辦法將對象在內存中的地址作為整數前往,這是一個很好的hash完成,他確保了分歧的對象具有分歧的hashcode。

關於Entry類的一點引見
一個map的界說是:一個映照鍵(key)到值(value)的對象。異常簡略對吧。

所以,在HashMap中必定有必定的機制來存儲這些鍵值對。使得,HashMap有一個 外部類Entry,看起來像如許。
 

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

固然,Entry類有屬性用來存儲鍵值對映照。key被final標志,除key和value ,我們還能看到兩個變量next和hash。接上去我們試著懂得這些變量的寄義。

put()辦法現實上做了甚麼
再進一步看put辦法的完成之前,我們有需要看一看Entry實例在數組中的存儲, HashMap中是如許界說的:
 

/**
   * The table, resized as necessary. Length MUST Always be a power of two.
   */
  transient Entry[] table;
如今再來看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>.)
*/
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;
}

讓我們一步一步的看
起首,檢討key能否為null,假如key是null值被存在table[0]的地位,由於null 的hashcode一直為0
接上去,經由過程key的hashCode()辦法盤算了這個key的hash值,這個hash值被用來 盤算存儲Entry對象的數組中的地位。JDK的設計者假定會有一些人能夠寫出異常差的hashCode()辦法,會湧現一些 異常年夜或許異常小的hash值。為懂得決這個成績,他們引入了別的一個hash函數,接收對象的hashCode(),並轉換 到合適數組的容量年夜小。

接著是indexFor(hash,table,length)辦法,這個辦法盤算了entry對象存儲 的精確地位。
接上去就是重要的部門,我們都曉得兩個不相等的對象能夠具有過雷同的 hashCode值,兩個分歧的對象是怎樣存儲在雷同的地位[叫做bucket]呢?
謎底是LinkedList。假如你記得,Entry類有一個next變量,這個變量老是指向 鏈中的下一個變量,這完整相符鏈表的特色。

所以,在產生碰撞的時刻,entry對象會被以鏈表的情勢存儲起來,當一個Entry 對象須要被存儲的時刻,hashmap檢討該地位能否已近有了一個entry對象,假如沒有就存在那邊,假如有了就檢討 她的next屬性,假如是空,以後的entry對象就作為曾經存儲的entry對象的下一個節點,順次類推。

假如我們給曾經存在的key存入另外一個value會怎樣樣的?邏輯上,舊的值將被替 換失落。在檢測了Entry對象的存儲地位後,hashmap將會遍歷誰人地位的entry鏈表,對每個entry挪用equals辦法 ,這個鏈表中的一切對象都具有雷同的hashCode()而equals辦法都不等。假如發明equals辦法有相等的就履行調換 。

在這類方法下HashMap就可以包管key的獨一性。

get辦法的任務機制
如今我們曾經懂得了HashMap中存儲鍵值對的機制。下一個成績是:如何從一個 HashMap中查詢成果。
其實邏輯跟put是一樣的,假如傳入的key有婚配就將該地位的value前往,假如 沒有就前往null.
 

/**
* 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>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 explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
*
* @see #put(Object, Object)
*/
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;
}

下面的代碼看起來跟put()辦法很像,除if (e.hash == hash && ((k = e.key) == key || key.equals(k)))。

留意點

  •     存儲Entry對象的數據構造是一個叫做Entry類型的table數組。
  •     數組中一個特定的索引地位稱為bucket,由於它可以包容一個LinkedList 的第一個元素的對象。
  •     Key對象的hashCode()須要用來盤算Entry對象的存儲地位。
  •     Key對象的equals()辦法須要用來保持Map中對象的獨一性。
  •     get()和put()辦法跟Value對象的hashCode和equals辦法有關。
  •     null的hashCode老是0,如許的Entry對象老是被存儲在數組的第一個地位

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved