Java での hashCode メソッドと等しいメソッドの正しい使用

高洛峰
リリース: 2016-12-16 10:25:34
オリジナル
1302 人が閲覧しました

この記事では、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() メソッドも提供する場合があります。

Java での hashCode メソッドと等しいメソッドの正しい使用

覚えておくべきこと

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 サイトに注目してください。


関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート