在學習hashCode()和equals()之間的關係以前, 咱們有必要先單獨瞭解他倆自身的特色.java
下面咱們從一個宏觀的角度引入hashCode()和equals()之間的關係程序員
以上的文字是我通過思考後得出的, 它有必定依據但並不是徹底可靠, 下面咱們根據HashMap的源碼(JDK1.8)和官方文檔來驗證這些推論是否正確.面試
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.編程
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
複製代碼
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
//在咱們建立HashMap對象的時候, 內存中並無爲HashMap分配表的空間, 直到往HashMap中put添加元素的時候才調用resize()方法初始化表
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;//同時肯定了表的長度
//((n - 1) & hash)肯定了要put的元素的位置, 若是要插入的地方是空的, 就能夠直接插入.
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {//若是發生了衝突, 就要在衝突位置的鏈表末尾插入元素
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
//關鍵!!!當判斷新加入的元素是否與已有的元素相同, 首先判斷的是hash值, 後面再調用equals()方法. 若是hash值不一樣是直接跳過的
e = p;
else if (p instanceof TreeNode)//若是衝突解決方案已經變成紅黑樹的話, 按紅黑樹的策略添加結點.
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {//解決衝突的方式還是鏈表
for (int binCount = 0; ; ++binCount) {//找到鏈表的末尾, 插入.
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);//插入以後要判斷鏈表的長度, 若是到達必定的值就可能要轉換爲紅黑樹.
break;
}//在遍歷的過程當中仍會不停地斷定當前key是否與傳入的key相同, 判斷的第一條件仍然是hash值.
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;//修改map的次數增長
if (++size > threshold)//若是hashMap的容量到達了必定值就要進行擴容
resize();
afterNodeInsertion(evict);
return null;
}
複製代碼
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
複製代碼
結束api