Java開發(fā)HashMap?key必須實現(xiàn)hashCode?equals方法原理
一、問題引入
平時在開發(fā)中,相信你多多少少都使用過HashMap,而當(dāng)你用自定義對象作為key時,很多人會告訴你:你必須要同時實現(xiàn)自定義對象的hashCode、equals方法,否者可能會出問題,于是你就實現(xiàn)了...
可是為什么呢?比如這里有自定義對象Person,構(gòu)造如下:
public class Person {
private String name;
private int age;
private float height;
}
欲將Person作為HashMap的key,放入哈希表中存儲信息。我們來探討一下,為什么要同時實現(xiàn)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方法都未實現(xiàn)
倘若你了解哈希表的基本構(gòu)造,可以畫出一個草圖:

我們并沒有實現(xiàn)hashCode、equals方法,為什么還能放入哈希表中呢?
- 因為
JDK會有默認(rèn)實現(xiàn)
在默認(rèn)的實現(xiàn)中:
- 利用
hashCode方法計算出的哈希值是不同的 - 利用
equals方法比較,p1和p2不是一個對象 - 所以放入哈希表中的大致結(jié)構(gòu)如上圖所示:
- 可能會被放入兩個桶
(不同哈希值計算出的索引不一樣) - 也可能會被放入一個桶
(不同哈希值也可能會計算出相同的索引),又因為是不同對象,所以會被串起來
- 可能會被放入兩個桶
三、只實現(xiàn)hashCode方法
如果我們實現(xiàn)了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;
}
如上實現(xiàn),既滿足了盡量用的所有信息,也使計算的值盡量唯一了
如果是現(xiàn)在,我們再來畫一幅草圖:

現(xiàn)在只實現(xiàn)了hashCode方法:
- 利用
hashCode方法計算出的哈希值是相同的 equals方法是默認(rèn)實現(xiàn),p1和p2不是一個對象- 所以放入哈希表中的大致結(jié)構(gòu)如上圖所示:
- 只會被放入一個桶(相同的哈希值計算出的索引相同),又因為是不同對象,所以會被串起來
四、只實現(xiàn)equals方法
如果我們實現(xiàn)了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));
}
如上實現(xiàn),如果兩個對象的age、name、height都相等,那么可以認(rèn)為是同一個對象
如果是現(xiàn)在:

現(xiàn)在只實現(xiàn)了equals方法:
hashCode方法是默認(rèn)實現(xiàn),計算出的哈希值是不同的- 利用
equals方法比較,p1和p2是同一個對象 - 所以放入哈希表中的大致結(jié)構(gòu)如上圖所示:
- 可能會被放入兩個桶
(計算出的索引不一樣) - 也可能會被放入一個桶
(不同哈希值也可能會計算出相同的索引),又因為是同一對象,所以p2的鍵和值會覆蓋掉p1的
- 可能會被放入兩個桶
五、hashCode、equals方法都實現(xiàn)
倘若我們用上面的實現(xiàn)方式,將hashCode和equals方法都實現(xiàn)了
來看看最終的結(jié)構(gòu):

現(xiàn)在hashCode、equals方法都實現(xiàn)了:
- 利用
hashCode方法計算出的哈希值是相同的 - 利用
equals方法比較,p1和p2是同一個對象
所以放入哈希表中的大致結(jié)構(gòu)如上圖所示:
- 只會被放入一個桶中
(相同的哈希值計算出的索引相同),又因為是同一對象,所以p2的鍵和值會覆蓋掉p1
六、總結(jié)
如果你想要用自定義對象作為HashMap的key,為什么hashCode、equals方法都要實現(xiàn)?
相信你看完了四種情況,應(yīng)該能說出個balabala...
那我們一起來balabala一下吧~
- 先利用
hashCode方法計算出哈希值:- 如果哈希值相同,在哈希表中計算出的索引肯定相同,會被放入一個桶中。這時候用
equals方法查看是否是相同的對象。- 如果是,用新的鍵和值覆蓋掉舊的;
- 如果不是就用鏈地址法將對象串起來
- 如果哈希值不同,在哈希表中計算的索引也可能相同,也就是可能會被放入一個桶,也可能會被放入兩個桶。
- 如果被放入一個桶中,同上一樣,檢查
equlas方法; - 如果放入兩個桶中,則不需要查看是否
equals
- 如果被放入一個桶中,同上一樣,檢查
- 如果哈希值相同,在哈希表中計算出的索引肯定相同,會被放入一個桶中。這時候用
一般的開發(fā)需求會是第四種,想要用p1和p2作為key存儲數(shù)據(jù),會認(rèn)為它們是同一個對象,它們是同一個key,也就只會存儲一份數(shù)據(jù)。所以如果不同時實現(xiàn)hashCode、equals方法,會有圖中的種種問題。
以上就是Java開發(fā)HashMap key必須實現(xiàn)hashCode equals方法原理的詳細內(nèi)容,更多關(guān)于Java開發(fā)HashMap key的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java刪除指定文件夾下的所有內(nèi)容的方法(包括此文件夾)
下面小編就為大家?guī)硪黄狫ava刪除指定文件夾下的所有內(nèi)容的方法(包括此文件夾) 。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-12-12
springboot?html調(diào)用js無效400問題及解決
這篇文章主要介紹了springboot?html調(diào)用js無效400的問題及解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-03-03
Java 數(shù)據(jù)結(jié)構(gòu)與算法系列精講之字符串暴力匹配
字符串暴力匹配算法是指在一個長字符串中暴力尋找是否包含某一子串所謂暴力匹配,就是不使用任何其他算法,將兩個字符串中的字符一一進行比對2022-02-02
SSH框架網(wǎng)上商城項目第20戰(zhàn)之在線支付平臺
這篇文章主要為大家詳細介紹了SSH框架網(wǎng)上商城項目第20戰(zhàn)之在線支付平臺,關(guān)于第三方支付的內(nèi)容從本文開始,感興趣的小伙伴們可以參考一下2016-06-06
Java字符串拼接+和StringBuilder的比較與選擇
Java 提供了兩種主要的方式:使用 "+" 運算符和使用 StringBuilder 類,本文主要介紹了Java字符串拼接+和StringBuilder的比較與選擇,感興趣的可以了解一下2023-10-10
Spring實戰(zhàn)之使用XML方式管理聲明式事務(wù)操作示例
這篇文章主要介紹了Spring實戰(zhàn)之使用XML方式管理聲明式事務(wù)操作,結(jié)合實例形式詳細分析了Spring XML方式管理聲明式事務(wù)具體步驟、配置、接口及使用技巧,需要的朋友可以參考下2020-01-01

