有面試官會問:你重寫過 hashcode和equals 麼,為什麼重寫equals時必須重寫hashCode方法?
equals和hashCode都是Object物件中的非final方法,它們設計的目的就是被用來覆蓋(override)的,所以在程式設計中還是經常需要處理這兩個方法.下面我們一起來看一下,它們到底有什麼區別,總結一波!
hashCode介紹
hashCode()的作用是獲取雜湊碼,也稱為雜湊碼,它實際上是返回一個int整數,這個雜湊碼的作用是確定該物件在雜湊表中的索引位置,hashCode()定義在JDK的Object.java中,這就意味著Java中的任何類都包含有hashCode() 函式.
equals介紹
equals()它的作用也是判斷兩個物件是否相等,
如果物件重寫了equals()方法,一般比較兩個物件的內容是否相等,
如果沒有重寫,比較兩個物件的地址是否相同,價於“==”,
同樣的,equals()定義在JDK的Object.java中,這就意味著Java中的任何類都包含有equals()函式.
hashCode() 和 equals() 有什麼關係?
如果該類不會在HashSet、 HashTable、 HashMap等這些本質是雜湊表的資料結構中用到,則hashCode()和equals()兩者之間是沒有關係的。
下面我們分析一下該類會在HashSet、 HashTable、 HashMap等這些本質是雜湊表的資料結構中用到時的關係:
equals相等的兩個物件的hashcode一定相等;
equals不相等的兩個物件的hashcode有可能相等.
示例程式碼
點選檢視程式碼
package com.yuanxiaohao;
import java.util.*;
public class TestHashCode {
public static void main(String[] args) {
test();
}
public static void test(){
System.out.println("######test######");
Set<Model> set =new HashSet<Model>();
Model a =new Model("猿小豪","20");
Model b =new Model("猿小豪","20");
set.add(a);
System.out.println("a.hashCode:"+a.hashCode());
set.add(b);
System.out.println("b.hashCode:"+b.hashCode());
System.out.println(set);
}
public static class Model {
private String name;
private String age;
public Model(String name, String age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Model)) return false;
Model model = (Model) o;
return name.equals(model.name) &&
age.equals(model.age);
}
// @Override
// public int hashCode() {
// return (name+age).hashCode();
// }
@Override
public String toString() {
return "Model{" +
"name='" + name + '\'' +
", age='" + age + '\'' +
'}';
}
}
}
執行結果
######test2######
a.hashCode:1163157884
b.hashCode:1956725890
[Model{name='猿小豪', age='20'}, Model{name='猿小豪', age='20'}]
結果分析
我們重寫了Model的equals(),但是很奇怪的發現HashSet中仍然有重複元素:a和b.
為什麼會出現這種情況呢?
這是因為雖然a和b的內容相等,但是它們的hashCode()不等,所以HashSet在新增a和b的時候,認為它們不相等.
HashSet的add方法原始碼分析
HashSet中的add方法實際呼叫的是HashMap中的put方法,而HashMap的put方法中,使用key作為引數,在hash方法中用key的hashCode()計算出hash值,然後在putVal方法中使用計算出的hash值進行比較,如果hash值相同,再通過equals()比較key值是否相同,如果都相同,則覆蓋原有的Node物件,否則建立新的Node物件放入連結串列中.
總結
如果類使用在雜湊表的集合物件中,要判斷兩個物件是否相同,除了要重寫equals()之外,也要按照規則重寫hashCode()函式,否則會出現”equals相等的兩個物件的hashcode不相等”的情況,從而在使用相關集合時,引起與自己的預期不相符的情況.
補充
至於為什麼先使用hash值判斷再使用equals.
個人理解:
在計算存放陣列下標的過程中,hash值已經通過hashCode計算得到了,後面就可以直接拿來用了,這樣就減少了equals次數,提高了效率.