首頁  >  文章  >  Java  >  Java 中正確使用 hashCode 和 equals 方法

Java 中正確使用 hashCode 和 equals 方法

高洛峰
高洛峰原創
2016-12-16 10:25:341293瀏覽

在這篇文章中,我將告訴大家我對hashCode和equals方法的理解。我將討論他們的預設實現,以及如何正確的重寫他們。我也將使用Apache Commons提供的工具包做一個實作。

目錄:

hashCode()和equals()的用法

重寫預設實作

使用Apache Commons Lang包重寫hashCode()和equals()

使用Apache Commons Lang包重寫hashCode()和equals()





ORM的時候特別要注意的

hashCode()和equals()定義在Object類別中,這個類別是所有java類別的基類,所以所有的java類別都繼承這兩個方法。


使用hashCode()和equals()

Java 中正確使用 hashCode 和 equals 方法hashCode()方法被用來取得給定物件的唯一整數。這個整數被用來確定物件被儲存在HashTable類似的結構中的位置。預設的,Object類別的hashCode()方法傳回這個物件儲存的記憶體位址的編號。

重寫預設的實作

如果你不重寫這兩個方法,將幾乎不遇到任何問題,但是有的時候程式要求我們必須改變一些物件的預設實作。

來看看這個例子,讓我們建立一個簡單的類別Employee

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;
    }
}

上面的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()方法。 

🎜🎜🎜需要注意記住的事情🎜🎜盡量保證使用物件的同一個屬性來產生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()就不會出現這個問題。 🎜🎜🎜🎜🎜更多Java 中正確使用 hashCode 和 equals 方法相關文章請關注PHP中文網! 🎜🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn