Java開發HashMap key必須實現hashCode equals方法原理
一、問題引入
平時在開發中,相信你多多少少都使用過HashMap
,而當你用自定義對象作為key
時,很多人會告訴你:你必須要同時實現自定義對象的hashCode、equals
方法,否者可能會出問題,於是你就實現瞭…
可是為什麼呢?比如這裡有自定義對象Person
,構造如下:
public class Person { private String name; private int age; private float height; }
欲將Person
作為HashMap的key
,放入哈希表中存儲信息。我們來探討一下,為什麼要同時實現hashCode、equals
方法吧~
Person p1 = new Person("ciusyan", 21, 1.8f); Person p2 = new Person("ciusyan", 21, 1.8f); Map<Person, String> map = new HashMap<>(); map.put(p1, "Ciusyan"); map.put(p2, "Zhiyan");
首先要明確:
hashCode
方法用於計算出對象的哈希值equlas
方法用於比較兩個對象是否相等
二、hashCode、equals方法都未實現
倘若你瞭解哈希表的基本構造,可以畫出一個草圖:
我們並沒有實現hashCode、equals
方法,為什麼還能放入哈希表中呢?
- 因為
JDK
會有默認實現
在默認的實現中:
- 利用
hashCode
方法計算出的哈希值是不同的 - 利用
equals
方法比較,p1和p2
不是一個對象 - 所以放入哈希表中的大致結構如上圖所示:
- 可能會被放入兩個桶
(不同哈希值計算出的索引不一樣)
- 也可能會被放入一個桶
(不同哈希值也可能會計算出相同的索引)
,又因為是不同對象,所以會被串起來
- 可能會被放入兩個桶
三、隻實現hashCode方法
如果我們實現瞭hashCode
方法,會有什麼不同呢?
@Override public int hashCode() { int hash = Integer.hashCode(age); hash = hash * 31 + Float.hashCode(height); hash = hash * 31 + (name == null ? 0 : name.hashCode()); return hash; }
如上實現,既滿足瞭盡量用的所有信息,也使計算的值盡量唯一瞭
如果是現在,我們再來畫一幅草圖:
現在隻實現瞭hashCode
方法:
- 利用
hashCode
方法計算出的哈希值是相同的 equals
方法是默認實現,p1和p2
不是一個對象- 所以放入哈希表中的大致結構如上圖所示:
- 隻會被放入一個桶(相同的哈希值計算出的索引相同),又因為是不同對象,所以會被串起來
四、隻實現equals方法
如果我們實現瞭equals
方法,會有什麼不同呢?
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || o.getClass() != getClass()) return false; Person p = (Person) o; return p.age == age && p.height == height && (Objects.equals(name, p.name)); }
如上實現,如果兩個對象的age、name、height
都相等,那麼可以認為是同一個對象
如果是現在:
現在隻實現瞭equals
方法:
hashCode
方法是默認實現,計算出的哈希值是不同的- 利用
equals
方法比較,p1和p2
是同一個對象 - 所以放入哈希表中的大致結構如上圖所示:
- 可能會被放入兩個桶
(計算出的索引不一樣)
- 也可能會被放入一個桶
(不同哈希值也可能會計算出相同的索引)
,又因為是同一對象,所以p2的鍵和值會覆蓋掉p1的
- 可能會被放入兩個桶
五、hashCode、equals方法都實現
倘若我們用上面的實現方式,將hashCode和equals
方法都實現瞭
來看看最終的結構:
現在hashCode、equals
方法都實現瞭:
- 利用
hashCode
方法計算出的哈希值是相同的 - 利用
equals
方法比較,p1和p2
是同一個對象
所以放入哈希表中的大致結構如上圖所示:
- 隻會被放入一個桶中
(相同的哈希值計算出的索引相同)
,又因為是同一對象,所以p2的鍵和值會覆蓋掉p1
六、總結
如果你想要用自定義對象作為HashMap的key
,為什麼hashCode、equals
方法都要實現?
相信你看完瞭四種情況,應該能說出個balabala…
那我們一起來balabala一下吧~
- 先利用
hashCode
方法計算出哈希值:- 如果哈希值相同,在哈希表中計算出的索引肯定相同,會被放入一個桶中。這時候用
equals
方法查看是否是相同的對象。- 如果是,用新的鍵和值覆蓋掉舊的;
- 如果不是就用鏈地址法將對象串起來
- 如果哈希值不同,在哈希表中計算的索引也可能相同,也就是可能會被放入一個桶,也可能會被放入兩個桶。
- 如果被放入一個桶中,同上一樣,檢查
equlas
方法; - 如果放入兩個桶中,則不需要查看是否
equals
- 如果被放入一個桶中,同上一樣,檢查
- 如果哈希值相同,在哈希表中計算出的索引肯定相同,會被放入一個桶中。這時候用
一般的開發需求會是第四種,想要用p1和p2
作為key
存儲數據,會認為它們是同一個對象,它們是同一個key
,也就隻會存儲一份數據。所以如果不同時實現hashCode、equals
方法,會有圖中的種種問題。
以上就是Java開發HashMap key必須實現hashCode equals方法原理的詳細內容,更多關於Java開發HashMap key的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 搞懂JAVAObject中的hashCode()
- Java數據結構之HashMap和HashSet
- 淺談java中為什麼重寫equals後需要重寫hashCode
- Java基礎之淺談hashCode()和equals()
- Java 中 hashCode() 與 equals() 的關系(面試)