在這篇文章中,我將概述我對方法覆蓋
Apache Commons 提供了兩個很棒的幫助器類別來呼叫方法
hashCode()
和的理解equals()
。我想談談它們的預設實現,以及如何正確地覆蓋它們。我還將撰寫有關使用 Apache Common 套件的幫助程式類別實作這些方法的文章。 這篇文章的內容:
- 使用
hashCode()
和equals()
. - 覆蓋預設行為。
- 覆蓋
hashCode()
並equals()
使用 Apache Commons Lang。 - 需要記住的重要事情。
- 使用 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() ...它將為您產生一個非常好的實作。 需要記住的重要事情。
- 始終使用相同的物件屬性來呼叫 and
hashCode()
和equals()
。就我們而言,我們使用了employee id
. - 此方法
equals()
必須是持久的(如果物件沒有改變,則該方法必須傳回相同的值)。 - 無論何時
a.equals(b)
,那麼a.hashCode()
一定是一樣的b.hashCode()
。 - 如果重寫一種方法,則必須重寫第二個方法。
使用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 這是我第一次嘗試翻譯。我試著盡可能接近作者想要表達的內容。如果您有任何意見,請寫在評論中。不要嚴格判斷:-))) 原創文章
GO TO FULL VERSION