equals(Object)
メソッドをオーバライドした場合は、必ず hashCode()
メソッドもオーバライドして正しく実装する必要があります。
hashCode()
を正しくオーバライドしないと、ハッシュ構造を用いたコンテナ(HashSet, HashMap など)に対してそのオブジェクトを格納した場合に、正常に動作しなくなってしまいます。
hashCode
は、下記の契約に基いて実装されなければいけません。
hashCode()
の返す値は、何度呼び出しても同じ値を返す必要がある(ただし、equals(Object)
において同値とみなされなくなるようなフィールドの変更があった場合は、hashCode()
の返す値は変化してよい)。equals(Object)
によって同値とみなされるオブジェクト同士の hashCode()
は同じでなければならない。
hashCode()
は、デフォルトではインスタンスごとに異なる値を返そうとするため、equals(Object)
を論理的な同値を判断するようにオーバライドしたら、hashCode()
も論理的に同じオブジェクトの場合には同じ値を返すように実装しなければいけません。equals(Object)
の結果が false
になるオブジェクト同士の hashCode()
は異なる値を返すのが望ましい。
Effective Java に、適度に理想的な hashCode
実装を行うための指針が示されており、Android の Object クラスの説明では、この指針に従ったサンプルコードが掲載されています。
@Override public int hashCode() {
// Start with a non-zero constant.
int result = 17;
// Include a hash for each field.
result = 31 * result + (booleanField ? 1 : 0);
result = 31 * result + byteField;
result = 31 * result + charField;
result = 31 * result + shortField;
result = 31 * result + intField;
result = 31 * result + (int) (longField ^ (longField >>> 32));
result = 31 * result + Float.floatToIntBits(floatField);
long doubleFieldBits = Double.doubleToLongBits(doubleField);
result = 31 * result + (int) (doubleFieldBits ^ (doubleFieldBits >>> 32));
result = 31 * result + Arrays.hashCode(arrayField);
result = 31 * result + referenceField.hashCode();
result = 31 * result + (nullableReferenceField == null ? 0 : nullableReferenceField.hashCode());
return result;
}
上記のコード内の xxxxField
という変数は、同値判定のために参照されるフィールドを示しています。
変数のプレフィックス (xxxx
) は、そのフィールドの型を示しており、それぞれの型の値をどのようにハッシュ値の計算のために使用すべきかが示されています。