hashCode()與equals()
有面試官會問:你重寫過 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次數,提高了效率.