この記事では、hashCode メソッドと平等メソッドについての私の理解を説明します。これらのデフォルトの実装と、それらを正しくオーバーライドする方法について説明します。 Apache Commons が提供するツールキットを使用して実装も行います。
目次:
hashCode()とequals()の使用法
デフォルトの実装をオーバーライドする
Apache Commons Langパッケージを使用してhashCode()とequals()を書き換える
覚えておくべきこと
使用する際ORM を使用する場合は、
hashCode() とquals() が Object クラスで定義されていることに特に注意する必要があります。このクラスはすべての Java クラスの基本クラスであるため、すべての Java クラスはこれら 2 つのメソッドを継承します。
hashCode()とequals()の使用
hashCode()メソッドは、指定されたオブジェクトの一意の整数を取得するために使用されます。この整数は、オブジェクトが HashTable のような構造内に格納される場所を決定するために使用されます。デフォルトでは、Object クラスの hashCode() メソッドは、このオブジェクトが格納されているメモリ アドレスの番号を返します。
デフォルトの実装をオーバーライドする
これら 2 つのメソッドをオーバーライドしない場合、ほとんど問題は発生しませんが、プログラムによっては、一部のオブジェクトのデフォルトの実装を変更する必要がある場合があります。
この例を見てみましょう。簡単なクラス 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 クラスには、いくつかの非常に基本的なプロパティとゲッターとセッターが含まれています。次に、2 人の従業員を比較する必要がある状況を考えてみましょう。
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 を出力することは間違いありませんが、実際には、上記 2 つのオブジェクトは従業員を表します。実際のビジネス ロジックでは 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); }
上記プログラムの出力結果は2つです。 2 つの従業員オブジェクトの等しいが true を返す場合、Set には 1 つのオブジェクトのみを格納する必要があります。何が問題ですか?
2 番目の重要なメソッド 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() メソッドとquals() メソッドを書き換えます。
Apache Commons パッケージには、hashCode() メソッドとquals() メソッドを生成するための 2 つの優れたクラスが用意されています。以下のプログラムをご覧ください。
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() メソッドとquals() メソッドも提供する場合があります。
覚えておくべきこと
hashCode() メソッドと equals() メソッドの生成にオブジェクトの同じプロパティが使用されていることを確認してください。この例では、従業員 ID を使用します。
eqauls メソッドは一貫性がなければなりません (オブジェクトが変更されていない場合、equals は同じ値を返す必要があります)
a.equals(b) が使用されるときは常に、a.hashCode() は b.hashCode と等しくなければなりません()。
両方を同時に書き直す必要があります。
ORM を使用する場合は特に注意してください
ORM を使用して一部のオブジェクトを処理する場合は、メンバー変数を直接参照するのではなく、hashCode() オブジェクトと equals() オブジェクトでゲッターとセッターを必ず使用する必要があります。 ORM のメンバー変数は遅延してロードされる場合があるため、これらの変数は getter メソッドが呼び出されたときにのみ実際に使用可能になります。
たとえば、この例では、e1.id == e2.id を使用するとこの問題が発生する可能性がありますが、e1.getId() == e2.getId() を使用するとこの問題は発生しません。
Java での hashCode および平等メソッドの正しい使用法に関連するその他の記事については、PHP 中国語 Web サイトに注目してください。