476

最近、この Developer Works Documentを読みました。

hashCode()このドキュメントは、効果的かつ正確に定義することに関するものequals()ですが、これら 2 つのメソッドをオーバーライドする必要がある理由がわかりません。

これらのメソッドを効率的に実装するための決定を下すにはどうすればよいですか?

4

31 に答える 31

641

Joshua Bloch は効果的な Java について語っています

equals() をオーバーライドするすべてのクラスで、hashCode() をオーバーライドする必要があります。そうしないと、Object.hashCode() の一般規約に違反することになり、クラスが HashMap、HashSet、Hashtable などのすべてのハッシュ ベースのコレクションと連携して適切に機能しなくなります。

オーバーライドequals()せずにオーバーライドhashCode()してMap.

このようなクラスがあり、 の 2 つのオブジェクトMyClassが等しい場合importantField( eclipse によって生成された場合)hashCode()とします。equals()

public class MyClass {
    private final String importantField;
    private final String anotherField;

    public MyClass(final String equalField, final String anotherField) {
        this.importantField = equalField;
        this.anotherField = anotherField;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((importantField == null) ? 0 : importantField.hashCode());
        return result;
    }

    @Override
    public boolean equals(final Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        final MyClass other = (MyClass) obj;
        if (importantField == null) {
            if (other.importantField != null)
                return false;
        } else if (!importantField.equals(other.importantField))
            return false;
        return true;
    }
}

あなたがこれを持っていると想像してください

MyClass first = new MyClass("a","first");
MyClass second = new MyClass("a","second");

オーバーライドのみequals

のみequalsがオーバーライドされている場合、myMap.put(first,someValue)最初に呼び出すとバケットにハッシュされ、呼び出すmyMap.put(second,someOtherValue)と他のバケットにハッシュされます (異なる があるためhashCode)。そのため、それらは同じですが、同じバケットにハッシュしないため、マップはそれを認識できず、両方ともマップに残ります。


equals()をオーバーライドする場合はオーバーライドする必要はありませんが、 の 2 つのオブジェクトが等しい場合にが等しいことがわかっているが をオーバーライドしないhashCode()場合、この特定のケースで何が起こるか見てみましょう。MyClassimportantFieldequals()

オーバーライドのみhashCode

オーバーライドするだけの場合は、最初にhashCode呼び出すときに、myMap.put(first,someValue)それを計算しhashCodeて、指定されたバケットに格納します。次に、呼び出すときに、(ビジネス要件に従って) 等しいため、 Map DocumentationmyMap.put(second,someOtherValue)に従って first を second に置き換える必要があります。

しかし問題は、equals が再定義されていないことです。そのため、マップがバケットをハッシュして反復処理するときに、true であるようなsecondオブジェクトがあるかどうかを調べても、あるものは見つかりません。ksecond.equals(k)second.equals(first)false

それが明らかだったことを願っています

于 2010-02-15T11:43:45.330 に答える
346

HashMapやなどのコレクションは、オブジェクトのハッシュコードHashSet値を使用して、オブジェクトをコレクション内に格納する方法を決定します。ハッシュコードは、コレクション内のオブジェクトを特定するために再度使用されます。

ハッシュ取得は、次の 2 段階のプロセスです。

  1. 適切なバケットを見つける (を使用hashCode())
  2. 適切な要素のバケットを検索します (を使用equals())

equals()なぜandをオーバーライドする必要があるかについての小さな例を次に示しhashcode()ます。

Employeeage と name の 2 つのフィールドを持つクラスを考えてみましょう。

public class Employee {

    String name;
    int age;

    public Employee(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this)
            return true;
        if (!(obj instanceof Employee))
            return false;
        Employee employee = (Employee) obj;
        return employee.getAge() == this.getAge()
                && employee.getName() == this.getName();
    }

    // commented    
    /*  @Override
        public int hashCode() {
            int result=17;
            result=31*result+age;
            result=31*result+(name!=null ? name.hashCode():0);
            return result;
        }
     */
}

クラスを作成し、Employeeオブジェクトをに挿入して、HashSetそのオブジェクトが存在するかどうかをテストします。

public class ClientTest {
    public static void main(String[] args) {
        Employee employee = new Employee("rajeev", 24);
        Employee employee1 = new Employee("rajeev", 25);
        Employee employee2 = new Employee("rajeev", 24);

        HashSet<Employee> employees = new HashSet<Employee>();
        employees.add(employee);
        System.out.println(employees.contains(employee2));
        System.out.println("employee.hashCode():  " + employee.hashCode()
        + "  employee2.hashCode():" + employee2.hashCode());
    }
}

次のように出力されます。

false
employee.hashCode():  321755204  employee2.hashCode():375890482

method のコメントを外しhashcode()、同じことを実行すると、出力は次のようになります。

true
employee.hashCode():  -938387308  employee2.hashCode():-938387308

2 つのオブジェクトが等しいと見なされる場合、それらのhashcodeも等しくなければならない理由がわかりましたか? そうしないと、クラス Object のデフォルトのhashcodeequals()メソッドは、2 つ以上のオブジェクトが等しいと見なされるようにメソッドがオーバーライドされた場合でも、事実上常に各オブジェクトに一意の番号が付けられるため、オブジェクトを見つけることができません。 . ハッシュコードがそれを反映していなければ、オブジェクトがどれほど等しいかは問題ではありません。もう一度: 2 つのオブジェクトが等しい場合、それらの hashcodeも等しくなければなりません。

于 2014-11-27T05:47:24.570 に答える
54

equals() をオーバーライドするすべてのクラスで、hashCode() をオーバーライドする必要があります。そうしないと、Object.hashCode() の一般規約に違反することになり、クラスが HashMap、HashSet、Hashtable などのすべてのハッシュ ベースのコレクションと連携して適切に機能しなくなります。


Joshua Bloch 著「Effective Java 」    より

equals()一貫して定義することによりhashCode()、クラスをハッシュベースのコレクションのキーとして使いやすくすることができます。hashCode の API ドキュメントで次のように説明されていjava.util.Hashtableます。

これらのメソッドを効率的に実装する方法に関するあなたの質問に対する最良の答えは、Effective Javaの第 3 章を読むことを提案することです。

于 2010-02-15T11:25:53.213 に答える
35

アイデンティティは平等ではありません。

  • オペレータ==テスト ID に等しい。
  • equals(Object obj)メソッドは等価性テストを比較します (つまり、メソッドをオーバーライドして等価性を伝える必要があります)

Java で equals メソッドと hashCode メソッドをオーバーライドする必要があるのはなぜですか?

まず、equals メソッドの使用法を理解する必要があります。

2 つのオブジェクトの違いを識別するために、equals メソッドをオーバーライドする必要があります。

例えば:

Customer customer1=new Customer("peter");
Customer customer2=customer1;
customer1.equals(customer2); // returns true by JVM. i.e. both are refering same Object
------------------------------
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
customer1.equals(customer2); //return false by JVM i.e. we have two different peter customers.

------------------------------
Now I have overriden Customer class equals method as follows:
 @Override
    public boolean equals(Object obj) {
        if (this == obj)   // it checks references
            return true;
        if (obj == null) // checks null
            return false;
        if (getClass() != obj.getClass()) // both object are instances of same class or not
            return false;
        Customer other = (Customer) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name)) // it again using bulit in String object equals to identify the difference 
            return false;
        return true; 
    }
Customer customer1=new Customer("peter");
Customer customer2=new Customer("peter");
Insteady identify the Object equality by JVM, we can do it by overring equals method.
customer1.equals(customer2);  // returns true by our own logic

これで hashCode メソッドは簡単に理解できるようになりました。

hashCode は、オブジェクトをHashMapHashSetなどのデータ構造に格納するために整数を生成します。

Customer上記の equals メソッドをオーバーライドしたとします。

customer1.equals(customer2);  // returns true by our own logic

オブジェクトをバケットに保存するときにデータ構造を操作している間(バケットはフォルダの派手な名前です)。組み込みのハッシュ技術を使用すると、上記の 2 つの顧客に対して 2 つの異なるハッシュコードが生成されます。したがって、同じ同一のオブジェクトを 2 つの異なる場所に格納しています。この種の問題を回避するには、次の原則に基づいて hashCode メソッドをオーバーライドする必要があります。

  • 等しくないインスタンスは、同じハッシュコードを持つ場合があります。
  • 等しいインスタンスは同じハッシュコードを返す必要があります。
于 2015-07-16T13:38:24.233 に答える
24

簡単に言えば、Object の equals-method は、プロパティが等しい場合でも、クラスの 2 つのインスタンスが意味的に等しい可能性があるため、参照の等価性をチェックします。これは、例えばHashMapSetのように equals や hashcode を利用するコンテナにオブジェクトを配置する場合に重要です。次のようなクラスがあるとしましょう:

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }
}

同じidを持つ 2 つのインスタンスを作成します。

Foo a = new Foo("id", "something");
Foo b = new Foo("id", "something else");

equals をオーバーライドしないと、次のようになります。

  • a.equals(b) は 2 つの異なるインスタンスであるため false
  • a. equals(a) は同じインスタンスであるため true です
  • b.equals(b) は同じインスタンスなので true です

正しい?多分、これがあなたが望むものなら。しかし、2 つの異なるインスタンスであるかどうかに関係なく、同じ ID を持つオブジェクトを同じオブジェクトにしたいとしましょう。equals (およびハッシュコード) をオーバーライドします。

public class Foo {
    String id;
    String whatevs;

    Foo(String id, String whatevs) {
        this.id = id;
        this.whatevs = whatevs;
    }

    @Override
    public boolean equals(Object other) {
        if (other instanceof Foo) {
            return ((Foo)other).id.equals(this.id);   
        }
    }

    @Override
    public int hashCode() {
        return this.id.hashCode();
    }
}

equals と hashcode の実装に関しては、Guava のヘルパー メソッドを使用することをお勧めします。

于 2010-02-15T11:29:45.297 に答える
15

概念を非常に簡単な言葉で説明しましょう。

まず、より広い観点からコレクションがあり、ハッシュマップはコレクション内のデータ構造の 1 つです。

equals と hashcode の両方のメソッドをオーバーライドする必要がある理由を理解するために、最初にハッシュマップとは何か、何が機能するかを理解する必要があります。

ハッシュマップは、データのキーと値のペアを配列形式で格納するデータ構造です。「a」の各要素がキーと値のペアである a[] としましょう。

また、上記の配列の各インデックスをリンク リストにすることで、1 つのインデックスに複数の値を含めることができます。

では、なぜハッシュマップが使用されるのでしょうか?

大きな配列を検索する必要がある場合、それぞれを検索するのは効率的ではないため、ハッシュ手法は、配列を何らかのロジックで前処理し、そのロジックに基づいて要素をグループ化できることを示しています。つまり、ハッシュ

例: 配列 1,2,3,4,5,6,7,8,9,10,11 があり、ハッシュ関数 mod 10 を適用すると、1,11 がグループ化されます。したがって、前の配列で 11 を検索する必要がある場合は、配列全体を反復する必要がありますが、グループ化すると反復の範囲が制限され、速度が向上します。上記のすべての情報を格納するために使用されるデータ構造は、簡単にするために 2 次元配列と考えることができます。

上記のハッシュマップとは別に、重複を追加しないこともわかります。これが equals と hashcode をオーバーライドしなければならない主な理由です

したがって、ハッシュマップの内部動作を説明すると言われたら、ハッシュマップが持つメソッドと、上記で説明した上記のルールにどのように従うかを見つける必要があります

したがって、ハッシュマップには put(K,V) と呼ばれるメソッドがあり、ハッシュマップによると、配列を効率的に分散し、重複を追加しないという上記の規則に従う必要があります

したがって、 put が行うことは、最初に指定されたキーのハッシュコードを生成して、値を入れるインデックスを決定することです。そのインデックスに何も存在しない場合、そこに何かが既に存在する場合、新しい値がそこに追加されます次に、そのインデックスでリンクされたリストの末尾に新しい値を追加する必要があります。ただし、ハッシュマップの目的の動作に従って、重複を追加しないでください。2 つの Integer オブジェクト aa=11,bb=11 があるとします。

オブジェクト クラスから派生したすべてのオブジェクトと同様に、2 つのオブジェクトを比較するための既定の実装では、オブジェクト内の値ではなく参照を比較します。したがって、上記の場合、意味的には等しいにもかかわらず、同等性テストに失敗し、同じハッシュコードと同じ値を持つ 2 つのオブジェクトが存在する可能性があり、重複が作成されます。オーバーライドすると、重複の追加を避けることができます。詳細作業を参照することもできます

import java.util.HashMap;


public class Employee {
    String name;
    String mobile;

    public Employee(String name,String mobile) {
        this.name = name;
        this.mobile = mobile;
    }
    
    @Override
    public int hashCode() {
        System.out.println("calling hascode method of Employee");
        String str = this.name;
        int sum = 0;
        for (int i = 0; i < str.length(); i++) {
            sum = sum + str.charAt(i);
        }
        return sum;
    }

    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        System.out.println("calling equals method of Employee");
        Employee emp = (Employee) obj;
        if (this.mobile.equalsIgnoreCase(emp.mobile)) {
            System.out.println("returning true");
            return true;
        } else {
            System.out.println("returning false");
            return false;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Employee emp = new Employee("abc", "hhh");
        Employee emp2 = new Employee("abc", "hhh");
        HashMap<Employee, Employee> h = new HashMap<>();
        //for (int i = 0; i < 5; i++) {
            h.put(emp, emp);
            h.put(emp2, emp2);
        //}
        
        System.out.println("----------------");
        System.out.println("size of hashmap: "+h.size());
    }
}
于 2015-03-03T18:33:17.760 に答える
13

hashCode():

hash-code メソッドのみをオーバーライドすると、何も起こりません。これhashCodeは、オブジェクト クラスとして各オブジェクトに対して常に new を返すためです。

equals():

equals メソッドのみをオーバーライドする場合、a.equals(b)が true の場合は、hashCodea と b が同じでなければならないことを意味しますが、hashCodeメソッドをオーバーライドしていないため、そうはなりません。

注 : hashCode()Object クラスのメソッドは、常にhashCode各オブジェクトに対して new を返します。

したがって、ハッシュ ベースのコレクションでオブジェクトを使用する必要がある場合は、 と の両方equals()をオーバーライドする必要がありますhashCode()

于 2013-07-29T11:31:44.343 に答える
12

Java は次のルールを設定します。

「Object クラスの equals メソッドを使用して 2 つのオブジェクトが等しい場合、hashcode メソッドはこれら 2 つのオブジェクトに同じ値を与える必要があります。」

したがって、クラスでオーバーライドする場合は、メソッドもオーバーライドしてこの規則に従うequals()必要があります。とのhashcode()両方のメソッドは、たとえば で値をキーと値のペアとして格納するために使用されます。一方をオーバーライドして他方をオーバーライドしない場合、そのようなオブジェクトをキーとして使用すると、 が意図したとおりに機能しない可能性があります。equals()hashcode()HashtableHashtable

于 2014-01-01T15:13:07.187 に答える
7

それらをオーバーライドしないと、Object のデフォルトの実装が使用されるためです。

インスタンスの等価性と hascode の値は、通常、オブジェクトを構成するものについての知識を必要とするため、具体的な意味を持つようにクラスで再定義する必要があります。

于 2010-02-15T11:20:56.063 に答える
6

@Lombo の回答に追加する

equals() をオーバーライドする必要があるのはいつですか?

オブジェクトの equals() のデフォルトの実装は

public boolean equals(Object obj) {
        return (this == obj);
}

これは、2 つのオブジェクトが同じメモリ アドレスを持つ場合にのみ等しいと見なされることを意味します。これは、オブジェクトをそれ自体と比較している場合にのみ真になります。

ただし、2 つのオブジェクトが 1 つ以上のプロパティに対して同じ値を持っている場合は、それらを同じと見なしたい場合があります (@Lombo の回答に示されている例を参照してください)。

したがってequals()、これらの状況でオーバーライドし、独自の平等条件を与えることになります。

equals() の実装に成功しましたが、うまく機能しています。

ユーザー定義クラスで「ハッシュ」ベースのコレクションを使用しない限り、問題ありません。HashMapしかし、将来、 orを使用したいと思うかもしれませんHashSet。そうしないoverrideと、hashCode() を「正しく実装」すると、これらのハッシュベースのコレクションは意図したとおりに機能しません。

equals のみをオーバーライドします (@Lombo の回答への追加)

myMap.put(first,someValue)
myMap.contains(second); --> But it should be the same since the key are the same.But returns false!!! How?

まず、HashMap は の hashCode がsecondと同じかどうかをチェックしfirstます。値が同じ場合にのみ、同じバケット内で等しいかどうかのチェックに進みます。

ただし、これら 2 つのオブジェクトの hashCode は異なります (既定の実装とはメモリ アドレスが異なるため)。したがって、同等性をチェックすることさえ気にしません。

オーバーライドされた equals() メソッド内にブレークポイントがある場合、それらが異なる hashCode を持っていると介入しません。 contains()チェックhashCode()し、それらが同じ場合にのみ、equals()メソッドを呼び出します。

HashMap ですべてのバケットの等価性をチェックできないのはなぜですか? したがって、 hashCode() をオーバーライドする必要はありません!!

次に、ハッシュベースのコレクションのポイントがありません。次のことを考慮してください。

Your hashCode() implementation : intObject%9.

以下は、バケットの形式で格納されているキーです。

Bucket 1 : 1,10,19,... (in thousands)
Bucket 2 : 2,20,29...
Bucket 3 : 3,21,30,...
...

たとえば、マップにキー 10 が含まれているかどうかを知りたいとします。すべてのバケットを検索しますか? または 1 つのバケットのみを検索しますか?

hashCode に基づいて、10 が存在する場合はバケット 1 に存在する必要があることを識別します。したがって、バケット 1 のみが検索されます!!

于 2014-12-09T06:06:06.100 に答える
5

値オブジェクトを使用する場合に便利です。以下はポートランド パターン リポジトリからの抜粋です。

値オブジェクトの例としては、数値、日付、金額、文字列などがあります。通常、それらは非常に広く使用されている小さなオブジェクトです。それらの ID は、オブジェクトの ID ではなく状態に基づいています。このようにして、同じ概念的な値オブジェクトの複数のコピーを持つことができます。

したがって、1998 年 1 月 16 日の日付を表すオブジェクトのコピーを複数持つことができます。これらのコピーはどれも互いに等しくなります。このような小さなオブジェクトの場合、日付を表す単一のオブジェクトに依存するよりも、新しいオブジェクトを作成して移動する方が簡単なことがよくあります。

値オブジェクトは、常に Java の .equals() (または Smalltalk の =) をオーバーライドする必要があります。(.hashCode() もオーバーライドすることを忘れないでください。)

于 2010-02-15T11:24:51.780 に答える
5
class A {
    int i;
    // Hashing Algorithm
    if even number return 0 else return 1
    // Equals Algorithm,
    if i = this.i return true else false
}
  • put('key','value') はhashCode()、バケットを決定するために使用してハッシュ値を計算し、equals()メソッドを使用して値がバケットに既に存在するかどうかを調べます。そうでない場合は追加され、それ以外の場合は現在の値に置き換えられます
  • get('key') はhashCode()、最初にエントリ (バケット) equals()を検索し、エントリの値を検索するために使用します

両方がオーバーライドされた場合、

マップ< A >

Map.Entry 1 --> 1,3,5,...
Map.Entry 2 --> 2,4,6,...

equals がオーバーライドされていない場合

マップ< A >

Map.Entry 1 --> 1,3,5,...,1,3,5,... // Duplicate values as equals not overridden
Map.Entry 2 --> 2,4,6,...,2,4,..

hashCode がオーバーライドされていない場合

マップ< A >

Map.Entry 1 --> 1
Map.Entry 2 --> 2
Map.Entry 3 --> 3
Map.Entry 4 --> 1
Map.Entry 5 --> 2
Map.Entry 6 --> 3 // Same values are Stored in different hasCodes violates Contract 1
So on...

HashCodeイコールコントラクト

  1. equal メソッドに従って等しい 2 つのキーは、同じ hashCode を生成する必要があります
  2. 同じ hashCode を生成する 2 つのキーが等しい必要はありません (上記の例では、すべての偶数が同じハッシュ コードを生成します)。
于 2015-07-14T09:04:36.103 に答える
4

私は説明を調べていました」「 hashCode のみをオーバーライドする場合、呼び出すときにmyMap.put(first,someValue)最初に取得し、その hashCode を計算して、指定されたバケットに格納します。次に、呼び出すときにmyMap.put(first,someOtherValue)、Map Documentation に従って first を second に置き換える必要があります。それらは等しいためです。 (私たちの定義によると)。」:

追加する2回目はmyMap、次のような「2番目の」オブジェクトにする必要があると思いますmyMap.put(second,someOtherValue)

于 2010-11-12T05:49:00.257 に答える
4

他の 2 つの (B) (C) を集約するクラス (A) があり、(A) のインスタンスをハッシュテーブル内に格納する必要があるとします。デフォルトの実装ではインスタンスの区別のみが許可され、(B) と (C) による区別は許可されません。したがって、 A の 2 つのインスタンスは等しい可能性がありますが、デフォルトでは、それらを正しい方法で比較することはできません。

于 2010-02-15T11:22:07.403 に答える
3

Java の Equals メソッドと Hashcode メソッド

これらは、すべてのクラス (カスタム クラスおよび Java API で定義されたその他のクラス) のスーパー クラスである java.lang.Object クラスのメソッドです。

実装:

public boolean equals(Object obj)

public int hashCode()

ここに画像の説明を入力

public boolean equals(Object obj)

このメソッドは、2 つのオブジェクト参照 x と y が同じオブジェクトを参照しているかどうかを単純にチェックします。つまり、x == y かどうかをチェックします。

これは再帰的です:任意の参照値 x に対して、x.equals(x) は true を返す必要があります。

これは対称的です:任意の参照値 x および y について、y.equals(x) が true を返す場合に限り、x.equals(y) は true を返す必要があります。

これは推移的です:任意の参照値 x、y、および z に対して、x.equals(y) が true を返し、y.equals(z) が true を返す場合、x.equals(z) は true を返す必要があります。

一貫性があります。任意の参照値 x および y に対して、x.equals(y) の複数の呼び出しは一貫して true を返すか、一貫して false を返します。ただし、オブジェクトの equals 比較で使用される情報が変更されていない場合に限ります。

null 以外の参照値 x の場合、x.equals(null) は false を返す必要があります。

public int hashCode()

このメソッドは、このメソッドが呼び出されたオブジェクトのハッシュ コード値を返します。このメソッドはハッシュ コード値を整数として返し、Hashtable、HashMap、HashSet などのハッシュ ベースのコレクション クラスのためにサポートされています。このメソッドは、equals メソッドをオーバーライドするすべてのクラスでオーバーライドする必要があります。

hashCode の一般的な契約は次のとおりです。

Java アプリケーションの実行中に同じオブジェクトに対して複数回呼び出された場合は常に、オブジェクトの equals 比較で使用される情報が変更されていない限り、hashCode メソッドは一貫して同じ整数を返す必要があります。

この整数は、あるアプリケーションの実行から同じアプリケーションの別の実行まで一貫性を保つ必要はありません。

equals(Object) メソッドに従って 2 つのオブジェクトが等しい場合、2 つのオブジェクトのそれぞれで hashCode メソッドを呼び出すと、同じ整数結果が生成される必要があります。

equals(java.lang.Object) メソッドに従って 2 つのオブジェクトが等しくない場合、2 つのオブジェクトのそれぞれで hashCode メソッドを呼び出すと、異なる整数結果が生成される必要はありません。ただし、プログラマーは、等しくないオブジェクトに対して個別の整数結果を生成すると、ハッシュテーブルのパフォーマンスが向上する可能性があることに注意する必要があります。

等しいオブジェクトは、等しい限り同じハッシュ コードを生成する必要がありますが、等しくないオブジェクトは異なるハッシュ コードを生成する必要はありません。

資力:

JavaRanch

写真

于 2016-08-28T06:13:51.683 に答える
3

メソッド equals および hashcode は、オブジェクト クラスで定義されます。デフォルトでは、equals メソッドが true を返す場合、システムはさらに進んでハッシュ コードの値をチェックします。2 つのオブジェクトのハッシュ コードも同じ場合にのみ、オブジェクトは同じと見なされます。そのため、 equals メソッドのみをオーバーライドすると、オーバーライドされた equals メソッドが 2 つのオブジェクトが等しいことを示していても、システム定義のハッシュコードは 2 つのオブジェクトが等しいことを示さない場合があります。したがって、ハッシュ コードもオーバーライドする必要があります。

于 2013-07-28T08:06:24.623 に答える
2

以下の例では、Person クラスの equals または hashcode のオーバーライドをコメント アウトすると、このコードは Tom の注文の検索に失敗します。ハッシュコードのデフォルトの実装を使用すると、ハッシュテーブルのルックアップでエラーが発生する可能性があります。

私が以下に持っているのは、人によって人々の注文を引き出す単純化されたコードです。Person がハッシュテーブルのキーとして使用されています。

public class Person {
    String name;
    int age;
    String socialSecurityNumber;

    public Person(String name, int age, String socialSecurityNumber) {
        this.name = name;
        this.age = age;
        this.socialSecurityNumber = socialSecurityNumber;
    }

    @Override
    public boolean equals(Object p) {
        //Person is same if social security number is same

        if ((p instanceof Person) && this.socialSecurityNumber.equals(((Person) p).socialSecurityNumber)) {
            return true;
        } else {
            return false;
        }

    }

    @Override
    public int hashCode() {        //I am using a hashing function in String.java instead of writing my own.
        return socialSecurityNumber.hashCode();
    }
}


public class Order {
    String[]  items;

    public void insertOrder(String[]  items)
    {
        this.items=items;
    }

}



import java.util.Hashtable;

public class Main {

    public static void main(String[] args) {

       Person p1=new Person("Tom",32,"548-56-4412");
        Person p2=new Person("Jerry",60,"456-74-4125");
        Person p3=new Person("Sherry",38,"418-55-1235");

        Order order1=new Order();
        order1.insertOrder(new String[]{"mouse","car charger"});

        Order order2=new Order();
        order2.insertOrder(new String[]{"Multi vitamin"});

        Order order3=new Order();
        order3.insertOrder(new String[]{"handbag", "iPod"});

        Hashtable<Person,Order> hashtable=new Hashtable<Person,Order>();
        hashtable.put(p1,order1);
        hashtable.put(p2,order2);
        hashtable.put(p3,order3);

       //The line below will fail if Person class does not override hashCode()
       Order tomOrder= hashtable.get(new Person("Tom", 32, "548-56-4412"));
        for(String item:tomOrder.items)
        {
            System.out.println(item);
        }
    }
}
于 2016-03-24T13:16:51.853 に答える
2

hashCode()メソッドは、指定されたオブジェクトの一意の整数を取得するために使用されます。この整数は、このオブジェクトをデータ構造などHashTableに格納する必要がある場合に、バケットの場所を決定するために使用されます。HashMapデフォルトでは、オブジェクトのhashCode()メソッドは、オブジェクトが格納されているメモリ アドレスの整数表現を返します。

オブジェクトのメソッドは、オブジェクトを、またはhashCode()に挿入するときに使用されます。詳細については、Wikipedia.org を参照してください。HashTableHashMapHashSetHashTables

マップ データ構造にエントリを挿入するには、キーと値の両方が必要です。キーと値の両方がユーザー定義のデータ型である場合hashCode()、キーの によって、オブジェクトを内部的に格納する場所が決まります。マップからオブジェクトを検索する必要がある場合も、キーのハッシュ コードによって、オブジェクトを検索する場所が決まります。

ハッシュ コードは、内部的に特定の「領域」(またはリスト、バケットなど) のみを指します。異なるキー オブジェクトが同じハッシュ コードを持つ可能性があるため、ハッシュ コード自体は、正しいキーが見つかることを保証するものではありません。次にHashTable、この領域 (同じハッシュ コードを持つすべてのキー) を反復し、キーのequals()メソッドを使用して正しいキーを見つけます。正しいキーが見つかると、そのキーに格納されているオブジェクトが返されます。

ご覧のとおり、hashCode()とのequals()メソッドの組み合わせは、 にオブジェクトを格納したり検索したりするときに使用されますHashTable

ノート:

  1. オブジェクトの同じ属性を常に使用して生成hashCode()し、equals()両方を生成します。私たちの場合と同様に、従業員 ID を使用しました。

  2. equals()一貫している必要があります (オブジェクトが変更されていない場合は、同じ値を返し続ける必要があります)。

  3. When a.equals(b), thena.hashCode()は と同じでなければなりませんb.hashCode()

  4. 一方をオーバーライドする場合は、もう一方をオーバーライドする必要があります。

http://parameshk.blogspot.in/2014/10/examples-of-comparable-comporator.html

于 2014-10-10T19:38:52.443 に答える
2

String クラスとラッパー クラスは、Object クラスとは異なるメソッドequals()の実装を持っています。hashCode()Object クラスの equals() メソッドは、内容ではなく、オブジェクトの参照を比較します。Object クラスの hashCode() メソッドは、内容が同じであるかどうかにかかわらず、単一のオブジェクトごとに異なるハッシュコードを返します。

Map コレクションを使用し、キーが Persistent 型、StringBuffer/builder 型の場合に問題が発生します。String クラスのように equals() と hashCode() をオーバーライドしないため、2 つの異なるオブジェクトを比較すると、同じ内容であっても equals() は false を返します。同じコンテンツキーを格納する hashMap を作成します。同じコンテンツ キーを格納するということは、Map は重複キーをまったく許可しないため、Map の規則に違反していることを意味します。したがって、クラス内の equals() メソッドと hashCode() メソッドをオーバーライドし、実装を提供して (IDE はこれらのメソッドを生成できます)、文字列の equals() および hashCode() と同じように機能し、同じコンテンツ キーを防止します。

equals() はハッシュコードに従って機能するため、 equals() とともに hashCode() メソッドをオーバーライドする必要があります。

さらに、equals() とともに hashCode() メソッドをオーバーライドすると、equals()-hashCode() 契約をそのまま維持するのに役立ちます。「2 つのオブジェクトが等しい場合、それらは同じハッシュ コードを持つ必要があります。」

hashCode() のカスタム実装を作成する必要があるのはいつですか?

私たちが知っているように、HashMap の内部動作はハッシングの原則に基づいています。エントリセットが保存される特定のバケットがあります。要件に応じて hashCode() 実装をカスタマイズして、同じカテゴリ オブジェクトを同じインデックスに格納できるようにします。メソッドを使用して値を Map コレクションに格納する場合put(k,v)、put() の内部実装は次のとおりです。

put(k, v){
hash(k);
index=hash & (n-1);
}

つまり、インデックスを生成し、インデックスは特定のキーオブジェクトのハッシュコードに基づいて生成されます。同じハッシュコード エントリセットが同じバケットまたはインデックスに格納されるため、このメソッドで要件に応じてハッシュコードを生成します。

それでおしまい!

于 2017-09-02T08:30:26.957 に答える
0

どちらのメソッドも Object クラスで定義されています。どちらも最も単純な実装です。したがって、これらのメソッドにさらに実装を追加する必要がある場合は、クラスでオーバーライドします。

例: オブジェクトの equals() メソッドは、参照に対する等価性のみをチェックします。したがって、その状態も比較する必要がある場合は、String クラスで行われるようにそれをオーバーライドできます。

于 2010-02-15T11:26:23.820 に答える
-3

Bah - 「equals() をオーバーライドするすべてのクラスで、hashCode() をオーバーライドする必要があります。」

[Joshua Bloch 著、Effective Java から?]

これは間違った方法ではありませんか?hashCode をオーバーライドすることは、ハッシュ キー クラスを作成していることを意味する可能性がありますが、equals をオーバーライドすることは確かにそうではありません。ハッシュキーとして使用されていない多くのクラスがありますが、他の理由で論理的等価性テスト方法が必要です。「equals」を選択すると、このルールを熱心に適用して、hashCode 実装を作成することが義務付けられる可能性があります。達成されるのは、テストされていないコードをコードベースに追加することだけです。これは、将来誰かをつまずかせるのを待っている悪です。また、必要のないコードを書くことは反アジャイルです。それは単に間違っています (そして、IDE によって生成されたものは、手作りの同等のものと互換性がない可能性があります)。

確かに、キーとして使用するために作成されたオブジェクトにインターフェイスを義務付けるべきでしたか? とにかく、オブジェクトはデフォルトの hashCode() および equals() imho を提供するべきではありませんでした。おそらく、多くの壊れたハッシュ コレクションが助長されたのでしょう。

とにかく、「ルール」は前後に書かれていると思います。当面は、等価性テスト メソッドに「equals」を使用しないようにします :-(

于 2016-02-19T18:00:16.763 に答える