重寫equals()方法為什么要重寫hashCode()方法,是面試中一個經(jīng)常會出現(xiàn)的一個問題赃绊〖认浚看完這篇文章,你一定對這個問題有更深的理解碧查。
equals方法和hashCode方法都是Object類中的方法运敢,我們來看看他們的源碼:
public boolean equals(Object obj) {
return (this == obj);
}
public native int hashCode();
可知,equals方法在其內(nèi)部是調(diào)用了"=="忠售,所以說在不重寫equals方法的情況下者冤,equals方法是比較兩個對象是否具有相同的引用,即是否指向了同一個內(nèi)存地址档痪。
而hashCode是一個本地方法涉枫,他返回的是這個對象的內(nèi)存地址。
知道了這些之后我們接著往下看腐螟。
hashCode的通用規(guī)定:
在應(yīng)用程序的執(zhí)行期間愿汰,只要對象的equals方法的比較操作所用到的信息沒有被修改困后,那么對同一個對象的多次調(diào)用,hashCode方法都必須始終返回同一個值衬廷。在一個應(yīng)用程序與另一個應(yīng)用程序的執(zhí)行過程中摇予,執(zhí)行hashCode方法所返回的值可以不一致。
如果兩個對象根據(jù)equals(Object)方法比較是相等的吗跋,那么調(diào)用這兩個對象中的hashCode方法都必須產(chǎn)生同樣的整數(shù)結(jié)果
如果兩個對象根據(jù)equals(Object)方法比較是不相等的侧戴,那么調(diào)用這兩個對象中的hashCode方法,則不一定要求hashCode方法必須產(chǎn)生不用的結(jié)果跌宛。但是程序員應(yīng)該知道酗宋,給不相等的對象產(chǎn)生截然不同的整數(shù)結(jié)果,有可能提高散列表的性能疆拘。
由上面三條規(guī)定可知蜕猫,如果重寫了equals方法而沒有重寫hashCode方法的話,就違反了第二條規(guī)定哎迄。相等的對象必須擁有相等的hash code回右。
接下來,我用一個程序來演示一下不重寫hashCode方法所帶來的嚴重后果:
public class Test {
public static void main(String[] args) {
Person person1 = new Person("TUCJVXCB");
Person person2 = new Person("TUCJVXCB");
Map<Person, Integer> hashMap = new HashMap<>();
hashMap.put(person1, 1);
System.out.println(person1.equals(person2));
System.out.println(hashMap.containsKey(person2));
}
static class Person {
private String name;
public Person(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Person) {
Person person = (Person) obj;
return name.equals(person.name);
}
return false;
}
}
}
以下是輸入結(jié)果
true
false
對于第一個輸出true我們很容易知道漱挚,因為我們重寫了equals方法翔烁,只要兩個對象的name屬性相同就會返回ture。但是為什么第二個為什么輸出的是false呢旨涝?就是因為我們沒有重寫hashCode方法蹬屹。所以我們得到一個結(jié)論:如果一個類重寫了equals方法但是沒有重寫hashCode方法,那么該類無法結(jié)合所有基于散列的集合(HashMap颊糜,HashSet)一起正常運作。
那么我們?nèi)绾谓鉀Q這個問題秃踩,很簡單衬鱼,重寫hashCode方法就行了。
@Override
public int hashCode() {
return name.hashCode();
}
經(jīng)過修改后憔杨,輸入如下:
true
true