Java apache commons HashCodeBuilder サンプルプログラム
HashCodeBuilderの説明(google翻訳)
Object.hashCode()メソッドの実装を支援します。
このクラスを使用すると、任意のクラスに対して適切なhashCodeメソッドを構築できます。これは、Joshua Bloch著「Effective Java」という本のルールに従います。良いhashCodeメソッドを書くことは、実際には非常に困難です。このクラスは、プロセスを簡素化することを目的としています。
次のアプローチが採用されています。データフィールドを追加すると、現在の合計に乗数が乗算され、そのデータタイプに関連する値が加算されます。たとえば、現在のhashCodeが17で、乗数が37の場合、整数45を追加すると、674のハッシュコード、つまり17 * 37 + 45が作成されます。
オブジェクトからの関連するすべてのフィールドは、hashCodeメソッドに含める必要があります。派生フィールドは除外することができます。一般に、equalsメソッドで使用されるフィールドは、hashCodeメソッドで使用する必要があります。
このクラスの書き込みコードを使用するには、次のようにします。
public class Person {
String name;
int age;
boolean smoker;
…public int hashCode() {
// you pick a hard-coded, randomly chosen, non-zero, odd number
// ideally different for each class
return new HashCodeBuilder(17, 37).
append(name).
append(age).
append(smoker).
toHashCode();
}
}必要に応じて、スーパークラスのhashCode()をappendSuper(int)を使用して追加できます。
あるいは、リフレクションを使用してテストするフィールドを決定する方法があります。これらのフィールドは通常非公開であるため、reflectionHashCodeメソッドはAccessibleObject.setAccessibleを使用してフィールドの可視性を変更します。適切な権限が正しく設定されていない限り、セキュリティマネージャの下では失敗します。明示的にテストするよりも遅くなります。
このメソッドの典型的な呼び出しは次のようになります。
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}HashCodeExcludeアノテーションを使用すると、reflectionHashCodeメソッドでフィールドが使用されないようにすることができます。
Object#hashCodeをオーバーライドする際の補助メソッドになります。
いちいち書くのが面倒なあなた向けのおすすめのソリューションです。
ただ、説明にも書かれていますが、hashCodeの実装は結構面倒です。
ですので、Mapなどのキーを作成する場合は、気を付けるか、何か基準を作成して実装しましょう。
ちなみに、javaの場合によく使うのがORMです。JPAの規格にのっとると、Entityのキーが複合キーの場合は、hashCodeをオーバーライドする必要があります。
HashCodeBuilder
package jp.pjin.tech.java; import jp.pjin.tech.java.domain.Dog; public class CommonsExample17 { public static void main(String[] args) throws Exception { Dog d1 = new Dog(); d1.setId(1); d1.setName("クロ"); d1.setType("柴犬"); Dog d2 = new Dog(); d2.setId(1); d2.setName("クロ"); d2.setType("パグ"); Dog d3 = new Dog(); d3.setId(1); d3.setName("シロ"); d3.setType("パグ"); System.out.println(d1.hashCode()); System.out.println(d2.hashCode()); System.out.println(d3.hashCode()); } }
Dog
package jp.pjin.tech.java.domain; import java.io.Serializable; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.apache.commons.lang3.builder.HashCodeExclude; public class Dog implements Serializable { private static final long serialVersionUID = 1L; private int id; private String name; @HashCodeExclude private String type; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } @Override public int hashCode() { return HashCodeBuilder.reflectionHashCode(this); } }
Dogには、フィールドが3つ定義されています。
id, name, type
typeに関しては、hashCodeの算出からはずしています。(@HashCodeExcludeがついています)
サンプルを見てみると、dog1とdog2はtypeのみ別の値をセットしています。ですので、同じhashCodeが出力されます。
それに対し、dog3は名前を変更しています。ですので、別のhash値が出力されます。
オブジェクトの標準のtoStringは、データ型@ハッシュコードという形式で、System.out.printlnを実行すると実行されます。
ですので、System.out.println(d1);などで、ハッシュコードを確認することも可能です。