JavaRush /Java Blog /Random-TW /在 Java 中使用 hashCode() 和 equals() 方法
Lenchik854
等級 0
Chernihiv

在 Java 中使用 hashCode() 和 equals() 方法

在 Random-TW 群組發布
在這篇文章中,我將概述我對方法hashCode()和的理解equals()。我想談談它們的預設實現,以及如何正確地覆蓋它們。我還將撰寫有關使用 Apache Common 套件的幫助程式類別實作這些方法的文章。 在 Java 中使用 hashCode() 和 equals() 方法 - 1這篇文章的內容:
  1. 使用hashCode()equals().
  2. 覆蓋預設行為。
  3. 覆蓋hashCode()equals()使用 Apache Commons Lang。
  4. 需要記住的重要事情。
  5. 使用 ORM 時要特別注意。
hashCode()和方法equals()在 class 中定義Object,該類別是 java 物件的父類別。因此,所有java物件都繼承了這些方法的預設實作。

使用 hashCode() 和 equals()

此方法hashCode()用於取得給定物件的唯一整數。當物件需要作為資料結構儲存在雜湊表(也稱為儲存桶)中時,該數字用於確定其在該表中的位置。預設情況下,物件的方法hashCode()會傳回儲存該物件的記憶體位置的編號。equals()顧名思義,該方法用於簡單地檢查兩個物件的相等性。此方法的預設實作只是檢查兩個物件的參考以查看它們是否等效。

覆蓋預設行為

只要您不重寫類別中的任何這些方法,一切都會正常運作。但有時應用程式需要更改某些物件的預設行為。讓我們舉一個例子,其中您有一個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有一些基本屬性和存取器方法。現在讓我們來看一個簡單的情況,我們需要比較類別的兩個物件Employee
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Печатает false в консоли
        System.out.println(e1.equals(e2));
    }
}
不需要有洞察力就能猜到上面寫的方法會回傳「false」。但考慮到這兩個物件是相同的,這實際上是正確的嗎?在即時應用中,該方法必須傳回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());
}
將此方法新增至您的類別中Employee,等效性檢查將傳回「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);

        //Печатает 'true'
        System.out.println(e1.equals(e2));

        Set employees = new HashSet();
        employees.add(e1);
        employees.add(e2);
        //Печатает два an object
        System.out.println(employees);
    }
}
該指令System.out.println(employee)列印兩個物件。如果兩個物件是等價的,並且Set只包含唯一的對象,那麼HashSet裡面應該只有一個實例,即 兩個物件都引用該類別的相同實例Employee。我們錯過了什麼?我們錯過了第二個重要的方法hashCode()。正如java文件所說,如果你重寫了方法equals(),那麼你就需要重寫該方法hashCode()。因此,讓我們為我們的類別添加另一個方法Employee
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
我們將此方法新增到我們的類別中一次,並且只會列印一個對象,因此,檢查 e1 和 e2 的等價性顯示 true。

覆蓋hashCode()equals()使用 Apache Commons Lang

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 中右鍵單擊類別 >> 來源 > 產生 hashCode() 和 equals() ...它將為您產生一個非常好的實作。 在 Java 中使用 hashCode() 和 equals() 方法 - 2需要記住的重要事情。
  1. 始終使用相同的物件屬性來呼叫 andhashCode()equals()。就我們而言,我們使用了employee id.
  2. 此方法equals()必須是持久的(如果物件沒有改變,則該方法必須傳回相同的值)。
  3. 無論何時a.equals(b),那麼a.hashCode()一定是一樣的b.hashCode()
  4. 如果重寫一種方法,則必須重寫第二個方法。

使用ORM時的特別注意

如果您正在處理 ORM (ru.wikipedia.org/wiki/ORM),那麼請務必使用 getters 並且永遠不要使用欄位參考hashCode()equals()這是因為在 ORM 中,欄位有時會使用延遲加載進行加載,並且在呼叫其 getter 之前無法存取。例如,在我們的班級中Employee,我們使用e1.id == e2.id. d 欄位完全有可能是i使用延遲載入來載入的。其中一個欄位可能為 0 或 null,我們將得到不正確的行為。但是,如果使用e1.getId() == e2.getId(),我們可以確定即使字段是使用延遲加載加載的;呼叫 getter 將首先填入該欄位。hashCode()這就是我對和方法的全部了解equals()。希望這對某個地方的人有幫助。祝你學業順利!!ps 這是我第一次嘗試翻譯。我試著盡可能接近作者想要表達的內容。如果您有任何意見,請寫在評論中。不要嚴格判斷:-))) 原創文章
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION