2

以下のコードをコンパイルして実行すると、次の結果が得られます。

o1==o2 ? true
Hash codes: 0 | 0
o1==o2 ? true
Hash codes: 1 | 8
o1==o2 ? true
Hash codes: 7 | 3
o1==o2 ? true
Hash codes: 68 | 10
o1==o2 ? true
Hash codes: 5 | 4

私が読んだことから、2 つのオブジェクトが等しい場合、それらの hashCodes も等しくなければなりません。では、このコードで例外やエラーが発生しないのはなぜでしょうか?

import java.io.*;
import java.lang.*;

public class EqualsAndHashCode {

    private int num1;
    private int num2;

    public EqualsAndHashCode(int num1, int num2) {
        this.num1 = num1;
        this.num2 = num2;
    }

    public static void main(String[] args) {
        for (int x=0; x < 5; x++) {
            EqualsAndHashCode o1 = new EqualsAndHashCode(x, x);
            EqualsAndHashCode o2 = new EqualsAndHashCode(x, x);
            System.out.println("o1==o2 ? " + o1.equals(o2));
            System.out.println("Hash codes: " + o1.hashCode() + " | " + o2.hashCode());
        }
    }

    public boolean equals(Object o) {
        return (this.getNum1() == ((EqualsAndHashCode)o).getNum1()) && (this.getNum2() == ((EqualsAndHashCode)o).getNum2());
    }

    public int hashCode() {
        return (int)(this.getNum1() / Math.random());
    }

    public int getNum1() { return num1; }
    public int getNum2() { return num2; }
}

EDIT I私の質問の背後にある前提は、hashCodeコントラクト( http://docs.oracle.com/javase/6/docs/api/java/lang/Object.html#hashCode() ) を取り巻く文言でした:

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

このルールは、コンパイル時または実行時に JVM によって適用され、契約に違反するとすぐにエラーまたは例外が発生すると想定していました...

4

7 に答える 7

2

2 つのオブジェクトが等しい場合、それらの hashCodes も等しい必要があります

上記は推奨事項であり、JVM によって義務付けられているわけではありません

この推奨事項の背後にある考え方は、HashMap などのハッシュされたコレクションに要素を格納するときに衝突を少なくすることです。

ハッシュコードの必要性、equals と hashcode のルールなどに関する非常に優れた記事:

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

于 2013-07-01T15:58:11.007 に答える
2

JVM は、メソッド コントラクトが trueであることを確認または検証しないためです。それらは単なるメソッドであり、必要なものを何でも返すことができます。

ただし、メソッド コントラクトのサポートに依存するコードは失敗する可能性があります。たとえば、EqualsAndHashCodeオブジェクトを で使用することはできません。ほとんどの場合、例外HashMapスローされるか、正しい値が返されません。

これはcompareTo()and TreeMaps-と同じことであり、必要なものをcompareTo()返すことができますが、インターフェイスintのメソッド コントラクトによって定義された一貫した順序を返さない場合、矛盾が検出されるとすぐに例外がスローされます。ComparableTreeMap

于 2013-07-01T15:59:48.353 に答える
0

hashcode() と equals() のデフォルトの実装は、定義した各クラスによって Object クラスから継承されます。特に HashMap などのデータ構造でコードが使用されている場合に、コードが正しく動作するためには、「クラスの 2 つのインスタンスが等しい場合、それらは同じ値を返す」ことを保証するデフォルトの実装をオーバーライドすることが重要です。 hashCode() メソッドが呼び出されたときの値".

2 つのオブジェクトの等価性の定義は、それらのクラスが表すドメインの概念に依存するため、クラスの作成者だけが「equals」および「hashcode」メソッドの実装に最適です。たとえば、「employeeId」属性の値が同じである場合、2 つの Employee オブジェクトは等しいと見なされます。これら 2 つは異なるインスタンスかもしれませんが、ドメイン (人事システムなど) の領域では、従業員 ID が同じであるため、同じです。ここで、Employee クラスの作成者は、「employeeId」属性を比較し、同じ場合に true を返す「equals」メソッドを実装する必要があります。同様に、作成者は、従業員 ID が同じ場合、2 つの Employee インスタンスの hashCode() が同じであることを確認する必要があります。

また、上記の Java の推奨事項を満たす hashCode をどのように記述すればよいか心配な場合は、Eclipse を使用して hashCode と equals を生成できます。

「2 つのオブジェクトが等しい場合、それらの hashCodes も等しい必要がある」という推奨事項にすぎませんが、クラスのオブジェクトが Set や Map などで使用されている場合、コードが誤動作を開始する可能性があるという事実に注意する必要があります。この推奨事項に準拠する「equals」および「hashCode」メソッドを作成しないでください。この推奨事項を無視したいのは、クラスが等しいかどうかがテストされないことが確実な場合だけです。このようなクラスの例としては、通常インスタンス化されてシングルトンとして使用される DAO クラスまたは Service クラスがあり、(通常のシナリオでは) 2 つの DAO クラスまたは Service クラスを比較する人はいません。

于 2013-07-01T16:08:44.347 に答える