hashCode() メソッド(1)−基本的な実装方法
equals() メソッドの姉妹ともいえる、hashCode() メソッドについて記述します。
hashCode() メソッドの仕様
- 属性に変化がない場合、hashCode() を複数回呼び出しても、常に同一の値を返し続けること。
- a.equals(b) = true ならば、a.hashCode() = b.hashCode() であること。
- a.equals(b) = false ならば、a.hashCode() != b.hashCode() でなくてもよい。但し、異なる値を返したほうが親切。
あと、「Effective Java」では、「equals() をオーバーライドするならば、必ず hashCode() をオーバーライドすべし!」と記述されています。
hashCode() メソッドの役割
コレクション・フレームワーク(java.util.Collection、List/Set/Map)の多くで、格納されている値同士の比較に使用されています。
HashMap#containsKey() では、key の hashCode を比較して、key があるか否かを判定しています。(JavaSE6 の実装で確認)
※「Effective Java」では、equals() で比較していると記述されていますが、実際は hashCode() でした。
なお、TreeSet や TreeMap では、hashCode ではなく Comparable#compareTo() で値を比較しています。(同じく JavaSE6 の実装で確認)
実装例
equals() メソッドの説明で使用した ComplicateObject を元に、hashCode() メソッドの実装例を記します。
import java.util.Date; public class ComplicateObject { // fields private boolean booleanValue; private byte byteValue; private char charValue; private short shortValue; private int intValue; private long longValue; private float floatValue; private double doubleValue; private String stringValue; private Date dateValue; @Override public int hashCode() { // ●基礎となる数を用意する。(ここでは17) int result = 17; // ●特定の数値(ここでは31)を掛ける。 // ・boolean : true なら1、false なら0。 result = 31 * result + (this.booleanValue ? 1 : 0); result = 31 * result + this.byteValue; result = 31 * result + this.charValue; result = 31 * result + this.shortValue; result = 31 * result + this.intValue; // ・long : f^(f>>>32) したものを int へキャスト result = 31 * result + (int) (this.longValue ^ (this.longValue >>> 32)); // ・float : Float.floatToIntBits() を呼び出す。 result = 31 * result + Float.floatToIntBits(this.floatValue); // ・double : Double.doubleToLongBits() を呼び出し(結果は long)、long と同じように加工する。 long l = Double.doubleToLongBits(this.doubleValue); result = 31 * result + (int) (l ^ (l >>> 32)); // ・値が null の場合は0を、null 以外の場合はそのオブジェクトの hashCode() を計算に使う。 result = (this.stringValue == null ? 31 * result + 0 : 31 * result + this.stringValue.hashCode()); result = (this.dateValue == null ? 31 * result + 0 : 31 * result + this.dateValue.hashCode()); return result; } // getter/setter/constructor は省略 }