面試的時(shí)候老是會(huì)問(wèn)到為什么要重寫(xiě)equals和hashcode方法。其實(shí)這個(gè)問(wèn)題里面包含好幾個(gè)問(wèn)題,我們通過(guò)源碼一一拆解就知道了!
equals() 比較的是什么?
hashcode() 方法是什么?
為什么要重寫(xiě)equals()?
為什么要重寫(xiě)hashcode() 方法,不重寫(xiě)可以?
首先我們要知道equals() 和hashcode() 是基類(lèi) java.lang.Object自帶的方法。
public native int hashCode();
public boolean equals(Object obj) {
return (this == obj);
}
hashcode() 是一個(gè)本地方法,返回的是jdk根據(jù)對(duì)象的地址或者字符串或者數(shù)字算出來(lái)的int類(lèi)型的數(shù)值(解釋來(lái)自于百度百科)。equals()方法默認(rèn)比較的就是對(duì)象本身,其實(shí)就是內(nèi)存地址。
那么有一個(gè)問(wèn)題,如果new了兩個(gè)屬性值一樣的對(duì)象,它們對(duì)于java來(lái)說(shuō)是不equal的,因?yàn)閷?duì)于java來(lái)說(shuō)兩個(gè)對(duì)象指向的是兩個(gè)不同的內(nèi)存地址。但是一般我們希望如果對(duì)象的屬性值一樣,那么我們就判斷這兩個(gè)對(duì)象相等。 那么就需要重寫(xiě)equals()。
下面我設(shè)計(jì)一個(gè)User類(lèi),包含id和realName屬性。我認(rèn)為只要id和name相同,那么就認(rèn)為兩個(gè)對(duì)象 相等。
ps :重寫(xiě) toString() 和equals() ,建議用IDE自帶的工具來(lái)生成。
public class User {
private String id;
private String realName;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getRealName() {
return realName;
}
public void setRealName(String realName) {
this.realName = realName;
}
public User(String id, String realName) {
this.id = id;
this.realName = realName;
}
@Override
public String toString() {
return "User{" +
"id='" + id + '\'' +
", realName='" + realName + '\'' +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
User user = (User) o;
return Objects.equals(id, user.id) &&
Objects.equals(realName, user.realName);
}
}
public class OverrideHashcode {
public static void main(String[] args) {
Set<User> data = new HashSet<>();
User a = new User("1001","小葉檀");
User b = new User("1001","小葉檀");
data.add(a);
data.add(b);
System.out.println("沒(méi)有重寫(xiě)hashcode前:"+data.toString());
System.out.println("兩個(gè)對(duì)象是否相等:"+(a.equals(b)));
}
}
運(yùn)行后打印結(jié)果:
沒(méi)有重寫(xiě)hashcode前:[User{id='1001', realName='小葉檀'}, User{id='1001', realName='小葉檀'}]
兩個(gè)對(duì)象是否相等:true
在沒(méi)重寫(xiě)hashcode()時(shí),默認(rèn)是以對(duì)象的內(nèi)存地址來(lái)參與計(jì)算hash碼的。
因?yàn)閮?nèi)存地址不同,那么得到的hash碼也不一樣,那么對(duì)于hashset來(lái)說(shuō)就被認(rèn)為是兩個(gè)不同的對(duì)象。
兩個(gè)相同的實(shí)例卻有不同的hashcode, 這樣就有點(diǎn)違背hashset的原則了。
所以需要重寫(xiě)hashcode()。
@Override
public int hashCode() {
return Objects.hash(id, realName);
}
重寫(xiě)完后再執(zhí)行main方法,發(fā)現(xiàn)set里面只有一個(gè)對(duì)象了。 大功告成!
總結(jié)
equals()默認(rèn)比較內(nèi)存地址,與業(yè)務(wù)而言意義不大,重寫(xiě)equals()為了結(jié)合業(yè)務(wù)體現(xiàn)對(duì)象的真實(shí)性。
hashcode()默認(rèn)是取的對(duì)象的內(nèi)存地址去計(jì)算散列碼,業(yè)務(wù)上認(rèn)為相同的實(shí)例所得到的hashcode卻不同。 重寫(xiě)hashcode()就是為了能運(yùn)用那些基于hash標(biāo)識(shí)對(duì)象唯一性的集合類(lèi)。
在這里估計(jì)就會(huì)有人問(wèn)到String的equals()默認(rèn)比較的就是里面的內(nèi)容,不是內(nèi)存地址。下一篇文章就整理跟String相關(guān)的面試題。