しかし、Java の一般的な連絡先によると、同じ値を返す必要があります。
Java のequals-hashCode契約では、2 つのオブジェクトが で等しい場合Object.equals、それらは からの同じハッシュコードを持っている必要がありますObject.hashCode。ただし、デフォルトの実装Object.equalsは参照等価であるため、2 つのインスタンスが同じである場合は、それらが同じインスタンスである場合に限ります。
したがって、特に 2 つのインスタンスt1とt2は、オーバーライドしていないため、実際には等しくありませんObject.equals。これらは参照として等しくないため、 ごとObject.equalsに等しくないため、 がhashCode異なる値を返す可能性があります。実際、契約には次のように明示的に記載されています。
2 つのオブジェクトがメソッドによって等しくない場合、2 つのオブジェクトのそれぞれでメソッドequals(java.lang.Object)を呼び出すと、hashCode異なる整数結果が生成される必要はありません。
equals-hashCodeしたがって、ここでは契約違反はありません。
したがって、オブジェクトについて、等価性の論理定義に従って異なるインスタンスを等しくしたい場合は、オーバーライドする必要がありますObject.equals。
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
if (this == obj) {
return true;
}
if (!(obj instanceof Test)) {
return false;
}
Test other = (Test)obj;
return this.i == other.i && this.j == other.j;
}
また、equals-hashCode契約ではオーバーライドObject.hashCodeも必要です。そうしないと、厄介なバグに遭遇します。
@Override
public int hashCode() {
int hash = 17;
hash = 31 * hash + this.i;
hash = 31 * hash + this.j;
return hash;
}
契約書の内容:
メソッドに従って 2 つのオブジェクトが等しい場合、2 つのオブジェクトのそれぞれでメソッドequals(Object)を呼び出すとhashCode、同じ整数の結果が生成される必要があります。
ここで、この要件を満たしているかどうかを見てみましょう。xとyが のインスタンスであり、 がTestを満たす場合、 とがあります。次に、明らかに、呼び出して、実行の各行で同じ値を保持する不変式がある場合。どちらの場合もそうであるため、明らかにこれは最初の行に当てはまります。が等しいかどうかにかかわらず同じ値を返すため、2 行目に保持されます。最後に、最後から 2 番目の行では、equalsも true であるため、両方の呼び出しで等しいままです。x.equals(y)truex.i == y.ix.j == y.jx.hashCode()y.hashCode()Test.hashCodehashhash17this.ithis == xthis == yx.iy.ihashx.jy.j
まだ説明していないコントラクトの最後の部分があることに注意してください。hashCodeこれは、Java アプリケーションの 1 回の実行中に一貫した値を返すという要件です。
hashCodeオブジェクトの equals 比較で使用される情報が変更されていない限り、メソッドは、Java アプリケーションの実行中に同じオブジェクトに対して複数回呼び出されるたびに、一貫して同じ整数を返す必要があります。
これの必要性は明らかです。hashCode同じアプリケーションの 1 回の実行中に戻り値を変更するとhashCode、オブジェクトの追跡に使用されるハッシュテーブルのようなデータ構造でオブジェクトが失われる可能性があります。特に、これが、ハッシュテーブルのようなデータ構造のキーであるオブジェクトを変更することが純粋な悪である理由です。しないでください。私は、それらが不変オブジェクトであるべきだと主張するところまで行きます。
実際、私が同じことをしているとき、StringまたはInteger彼らが同じを返しているときhashcode()。
それらは両方ともオーバーライドさObject.equalsれており、Object.hashCode.