あらゆるタイプのJavaオブジェクトのチェックサムを生成するソリューションを探しています。これは、同じオブジェクトを生成するアプリケーションを実行するたびに同じままです。
Object.hashCode()
で試しましたが、APIは
....この整数は、アプリケーションの1つの実行から同じアプリケーションの別の実行まで一貫している必要はありません。
私は同様の問題(XMLファイルの適切なハッシュコードの生成)を抱えていましたが、最善の解決策は MessageDigest またはより高速なものが必要な場合にMD5を使用することであることがわかりました: 高速MD5 。 Object.hashCode
は、高い一意性を保証するには、とにかく短すぎる(32ビットのみ)たびに同じになります。良いハッシュコードを計算するには、64ビットが最小だと思います。 MD5は128ビット長のハッシュコードを生成することに注意してください。これは、この状況で必要とされるよりもさらに多いはずです。
もちろん、MessageDigest
を使用するには、最初にオブジェクトをシリアル化(この場合はマーシャル)する必要があります。
public static String getChecksum(Serializable object) throws IOException, NoSuchAlgorithmException {
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(baos.toByteArray());
return DatatypeConverter.printHexBinary(thedigest);
} finally {
oos.close();
baos.close();
}
}
例
private BigInteger checksum(Object obj)throws IOException、NoSuchAlgorithmException { if(obj == null){ return BigInteger.ZERO; } ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); oos.close(); MessageDigest m = MessageDigest.getInstance( "SHA1"); m.update(baos.toByteArray()); return new BigInteger(1、m.digest()); }
シリアル化 を見るべきだと思います。シリアル化メカニズムは同様の問題を解決する必要があるため、どのように実装されているかを確認できます。
しかし、解決しようとしている問題を説明すると、おそらくより正確な解決策が得られます。
ソースを制御する場合は、hashCode()を実装して、実行間で一貫性を保つことができます。
allJavaオブジェクトに対してこれを実行できるようにしますか?
その場合、hashCode()
は機能しません。
一部のクラスでは、hashCode()
の定義がより厳密になり、実行全体での同等性が保証されます。たとえば、 String
には、明確に定義されたhashCode
実装があります。同様に List
と Set
は、それらに含まれるすべてのオブジェクトがである場合、明確に定義された値を持ちます。 には明確に定義された値があります(一般的な Collection.hashCode()
はnot値を明確に定義する必要があります)。
他のクラスの場合、チェックサムを作成するには、明確に定義された式を使用して再帰的にリフレクションを使用する必要があります。
Eclipse IDEを使用している場合は、([ソース]メニューの下に)ハッシュコードと等号関数を生成するアクションがあります。これにより、必要なクラスの属性を選択できます。ハッシュコード。これは、すでに提案されているHashCodeBuilderアプローチの使用に似ています。
または、オブジェクトをバイト配列にストリーミングして、そのMD5を生成することもできます。
Apache commonslangライブラリはHashCodeBuilder
クラスを提供し、クラスプロパティから要件を満たすハッシュコードを構築するのに役立ちます。
例:
public int checksum() {
// you pick a hard-coded, randomly chosen, non-zero, odd number
// ideally different for each class
return new HashCodeBuilder(17, 37).
append(property1).
append(property2).
append(property3).
toHashCode();
}
Commons Lang API を参照してください
ハッシュコードはOKです。指定されたクラスはequals
をオーバーライドし、契約の要求に応じてhashcode
もオーバーライドします。契約により、equals
がtrue
を返す場合、ハッシュコードは同じである必要があります。
またはクラスはequals
をオーバーライドしません。この場合、アプリケーションを別の方法で実行しても同じオブジェクトを生成できないため、問題はありません。
唯一の問題は、一部のクラス(Java APIからでも)がequals
のコントラクトを破ることです。
オブジェクト->文字列(たとえば、GSON-クラスのすべてのフィールドをリストしないようにシリアル化を記述する必要はありません)
String.hashCode()-> int(Object.hashCode()の代わりに!このhashCode()の実現は、メモリ内のアドレスではなく、Stringのコンテンツに依存します---さまざまなアプリの起動、さまざまなスレッドなどで使用できます。)
(または2.文字列-> md5)