hashCode()和equals()的用法


使用hashCode()和equals()

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

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。
這樣就可以了嗎?沒有,讓我們換一種測試方法來看看。

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

如果你使用Intellij IDEA或者其他的IDE,IDE也可能會提供生成良好的hashCode()方法和equals()方法。

需要注意記住的事情

  • 盡量保證使用對象的同一個屬性來生成hashCode()和equals()兩個方法。
  • 任何時候只要a.equals(b),那么a.hashCode()必須和b.hashCode()相等。
  • hashCode和equals兩者必須同時重寫。
  • 如果你使用ORM處理一些對象的話,你要確保在hashCode()和equals()對象中使用getter和setter而不是直接引用成員變量。因為在ORM中有的時候成員變量會被延時加載,這些變量只有當getter方法被調用的時候才真正可用。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM