hashCode()方法被用來獲取給定對象的惟一整數,這個整數被用來肯定對象被存儲在HashTable相似的結構中的位置,Object類的hashCode()方法返回這個對象存儲的內存地址的編號。java
equal()相等的兩個對象他們的hashCode()確定相等 hashCode()相等的兩個對象他們的equal()不必定相等
對比的時候算法
首先用hashCode()去對比,若是hashCode()不同,則表示這兩個對象確定不相等 若是hashCode()相同,此時再對比他們的equal(),若是equal()也相同,則表示這兩個對象是真的相同了
這樣的好處apache
hash散列算法,使得在hash表中查找一個記錄速度變O(1).每一個記錄都有本身的hashcode,散列算法按照hashcode把記錄放置在合適的位置.在查找一個記錄,首先先經過hashcode快速定位記錄的位置.而後再經過equals來比較是否相等.沒有hashcode,一個一個比較過來,時間就變O(N)了
這種大量的而且快速的對象對比通常使用的hash容器中,好比hashset,hashmap,hashtable等等,好比hashset裏要求對象不能重複,則他內部必然要對添加進去的每一個對象進行對比,而他的對比規則就是像上面說的那樣,先hashCode(),若是hashCode()相同,再用equal()驗證,若是hashCode()都不一樣,則確定不一樣,這樣對比的效率就很高了app
然而hashCode()和equal()同樣都是基本類Object裏的方法,而和equal()同樣,Object裏hashCode()裏面只是返回當前對象的地址,若是是這樣的話,那麼咱們相同的一個類,new兩個對象,因爲他們在內存裏的地址不一樣,則他們的hashCode()不一樣,因此這顯然不是咱們想要的,因此咱們必須重寫咱們類的hashCode()方法ide
public class Employee { private Integer id; private String firstname; private String lastName; private String department; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } } public class EqualsTest { public static void main(String[] args) { Employee e1 = new Employee(); Employee e2 = new Employee(); e1.setId(100); e2.setId(100); //Prints false in console System.out.println(e1.equals(e2)); } }
毫無疑問,上面的程序將輸出false
咱們須要重寫equals方法ui
public boolean equals(Object o) { if(o == null) { return false; } if (o == this) { return true; } if (getClass() != o.getClass()) { return false; } Employee e = (Employee) o; return (this.getId() == e.getId()); }
在上面的類中添加這個方法,EauqlsTest將會輸出true。this
import java.util.HashSet; import java.util.Set; public class EqualsTest { public static void main(String[] args) { Employee e1 = new Employee(); Employee e2 = new Employee(); e1.setId(100); e2.setId(100); //Prints 'true' System.out.println(e1.equals(e2)); Set<Employee> employees = new HashSet<Employee>(); employees.add(e1); employees.add(e2); //Prints two objects System.out.println(employees); } }
上面的程序輸出的結果是兩個。若是兩個employee對象equals返回true,Set中應該只存儲一個對象纔對,問題在哪裏呢?
咱們忘掉了第二個重要的方法hashCode()。就像JDK的Javadoc中所說的同樣,若是重寫equals()方法必需要重寫hashCode()方法。咱們加上下面這個方法,程序將執行正確。.net
@Override public int hashCode() { final int PRIME = 31; int result = 1; result = PRIME * result + getId(); return result; }
使用Apache Commons Lang包重寫hashCode() 和equals()方法
Apache Commons 包提供了兩個很是優秀的類來生成hashCode()和equals()方法。看下面的程序。code
import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; public class Employee { private Integer id; private String firstname; private String lastName; private String department; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } @Override public int hashCode() { final int PRIME = 31; return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME). toHashCode(); } @Override public boolean equals(Object o) { if (o == null) return false; if (o == this) return true; if (o.getClass() != getClass()) return false; Employee e = (Employee) o; return new EqualsBuilder(). append(getId(), e.getId()). isEquals(); } }
若是你使用Eclipse或者其餘的IDE,IDE也可能會提供生成良好的hashCode()方法和equals()方法。 對象
須要注意記住的事情
儘可能保證使用對象的同一個屬性來生成hashCode()和equals()兩個方法。在咱們的案例中,咱們使用員工id。
eqauls方法必須保證一致(若是對象沒有被修改,equals應該返回相同的值)
任什麼時候候只要a.equals(b),那麼a.hashCode()必須和b.hashCode()相等。
二者必須同時重寫。
當使用ORM的時候特別要注意的
若是你使用ORM處理一些對象的話,你要確保在hashCode()和equals()對象中使用getter和setter而不是直接引用成員變量。由於在ORM中有的時候成員變量會被延時加載,這些變量只有當getter方法被調用的時候才真正可用。
例如在咱們的例子中,若是咱們使用e1.id == e2.id則可能會出現這個問題,可是咱們使用e1.getId() == e2.getId()就不會出現這個問題。