Java中的超類java.lang.Object 有兩個(gè)非常重要的方法:
public boolean equals(Object obj)
public int hashCode()
這兩個(gè)方法最開發(fā)者來說是十分重要的,必須清楚的理解,但實(shí)際上充择,甚至很多經(jīng)驗(yàn)豐富的Java開發(fā)者有時(shí)候也沒有真正搞清楚這兩個(gè)方法的使用和原理。當(dāng)我們自定義了對(duì)象,并且想要將自定義的對(duì)象加到Map中時(shí)边锁,我們就必須對(duì)自定義的對(duì)象重寫這兩個(gè)方法,才能正確使用Map波岛。我們接下來將用這篇文章指出在使用hashcode和equals方法時(shí)茅坛,經(jīng)常范的錯(cuò)誤,并指出如何正確的使用這兩個(gè)方法则拷,以及這兩個(gè)方法工作的原理贡蓖。
常見的誤區(qū)
看下面這段代碼:
import java.util.HashMap;
public class HashCodeEqual {
public static void main(String[] args) {
Apple a1 = new Apple("Blue");
Apple a2 = new Apple("Green");
HashMap<Apple, Integer> map = new HashMap<>();
map.put(a1, 10);
map.put(a2, 20);
System.out.println(map.get(new Apple("Green")));
}
}
class Apple {
public String color;
public Apple(String color) {
this.color = color;
}
@Override
public boolean equals(Object obj) {
if(! (obj instanceof Apple))
return false;
if(obj == this)
return true;
return this.color.equals(((Apple)obj).color);
}
}
我們執(zhí)行上面這段代碼
卻發(fā)現(xiàn)與我們預(yù)想的結(jié)果并不一樣,我們想取出map中顏色為Green的apple煌茬,最后卻得到一個(gè)null值斥铺,這說明map沒有我們需要的顏色為green的apple對(duì)象,但實(shí)際上坛善,我們明明向其中添加了一個(gè)顏色為green的apple對(duì)象晾蜘,也重寫了equals方法,為什么最后卻取不出這個(gè)對(duì)象呢眠屎?
![Upload Paste_Image.png failed. Please try again.]
錯(cuò)誤出現(xiàn)的原因
這個(gè)問題引起的原因是因?yàn)槲覀儧]有重寫“hashCode”方法剔交,這就需要我們深入理解equals方法和hashCode方法的原理:
- 如果兩個(gè)對(duì)象是相等的,那么他們必須擁有一樣的hashcode改衩,這是第一個(gè)前提
- 如果兩個(gè)對(duì)象有一樣的hashcode岖常,但仍不一定相等,因?yàn)檫€需要第二個(gè)要求燎字,也就是equals方法的判斷腥椒。
其實(shí),map判斷對(duì)象的方法就是先判斷hashcode是否相等候衍,如果相等再判斷equals方法是否返回true笼蛛,只有同時(shí)滿足兩個(gè)條件,最后才會(huì)被認(rèn)為是相等的蛉鹿。
Map查找元素比線性搜索更快滨砍,這是因?yàn)閙ap利用hashkey去定位元素,這個(gè)定位查找的過程分成兩步,內(nèi)部原理中惋戏,map將對(duì)象存儲(chǔ)在類似數(shù)組的數(shù)組的區(qū)域领追,所以要經(jīng)過兩個(gè)查找,先找到hashcode相等的响逢,然后在再在其中按線性搜索使用equals方法绒窑,通過這兩部來查找一個(gè)對(duì)象。
就像上圖這個(gè)結(jié)構(gòu)舔亭,每個(gè)hashcode對(duì)應(yīng)一個(gè)桶些膨,每個(gè)tongli桶里還有多個(gè)對(duì)象,確定桶的方法是hashCode钦铺,在桶中遍歷線性查找的方法是equals订雾。
在Object中的默認(rèn)的hashCode方法的實(shí)現(xiàn)是為不同的對(duì)象返回不同的hashcode,因此如果我們不重寫hashcode方法,那么沒有任何兩個(gè)對(duì)象會(huì)是相等的矛洞,因?yàn)閛bject類中的hashcode實(shí)現(xiàn)是為不同的對(duì)象返回不同的hashcode洼哎。
所以,我們就搞清楚了上一段代碼出錯(cuò)的原因沼本,由于沒有重寫hashcode方法噩峦,所有的對(duì)象都是不一樣的,所以我們需要重寫hashcode方法擅威,讓顏色的對(duì)象的hashcode是一樣的壕探,比較直接的寫法就是直接用color的length作為hashcode。
public int hashCode(){
return this.color.length();
}
** 切記郊丛,一定要同時(shí)重寫hashCode和equals方法 **