在這篇文章中,我將告訴大家我對hashCode和equals方法的理解。我將討論他們的預設實現,以及如何正確的重寫他們。我也將使用Apache Commons提供的工具包做一個實作。
目錄:
hashCode()和equals()的用法
重寫預設實作
使用Apache Commons Lang包重寫hashCode()和equals()
使用Apache Commons Lang包重寫hashCode()和equals() ORM的時候特別要注意的
hashCode()方法被用來取得給定物件的唯一整數。這個整數被用來確定物件被儲存在HashTable類似的結構中的位置。預設的,Object類別的hashCode()方法傳回這個物件儲存的記憶體位址的編號。
重寫預設的實作
如果你不重寫這兩個方法,將幾乎不遇到任何問題,但是有的時候程式要求我們必須改變一些物件的預設實作。
來看看這個例子,讓我們建立一個簡單的類別Employeepublic 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; } }上面的Employee類別只是有一些非常基礎的屬性和getter、setter.現在來考慮一個你需要比較兩個employee的情形。
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,但是,事實上上面兩個物件代表的是透過一個employee。真正的商業邏輯希望我們回傳true。
為了達到這個目的,我們需要重寫equals方法。
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。
So are we done?沒有,讓我們換個測試方法來看。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()方法。我們加上下面這個方法,程式將執行正確。
@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()方法。看下面的程式。
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()方法。