我正在寻找一种解决方案,用于为任何类型的Java对象生成校验和,并且该校验和对于生成相同对象的应用程序的每次执行都保持不变。
我尝试使用Object.hashCode()
,但API指出:
....这个整数在应用程序的一个执行到相同应用程序的另一个执行之间不需要保持一致。
我正在寻找一种解决方案,用于为任何类型的Java对象生成校验和,并且该校验和对于生成相同对象的应用程序的每次执行都保持不变。
我尝试使用Object.hashCode()
,但API指出:
....这个整数在应用程序的一个执行到相同应用程序的另一个执行之间不需要保持一致。
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();
}
}
我曾经遇到过类似的问题(为XML文件生成好的哈希值),后来发现最好的解决方案是使用MessageDigest中的MD5,或者如果需要更快的速度,则可以使用Fast MD5。请注意,即使Object.hashCode
每次都相同,它也太短了(仅32位)无法确保高度唯一性。我认为64位是计算良好哈希码的最低要求。请注意,MD5生成的哈希码长度为128位,这甚至比在此情况下所需的长度还要长。
当然,要使用MessageDigest
,您需要首先序列化(在您的情况下进行编组)对象。
例子
private BigInteger checksum(Object obj) throws IOException, NoSuchAlgorithmException {
// 如果对象为空,则返回0 if (obj == null) { return BigInteger.ZERO; }
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(obj); oos.close();
// 创建SHA1实例并更新数据 MessageDigest m = MessageDigest.getInstance("SHA1"); m.update(baos.toByteArray());
// 返回摘要结果 return new BigInteger(1, m.digest()); }
您是否希望能够对所有Java对象执行此操作?
在这种情况下,hashCode()
不起作用。
对于某些类,hashCode()
具有更严格的定义,可以保证在多次执行中相等。例如,String
具有明确定义的 hashCode
实现。类似地,List
和 Set
也具有明确定义的值,前提是它们包含的所有对象也具有明确定义的值(请注意,一般的Collection.hashCode()
不需要该值是明确定义的)。
对于其他类,您将必须使用反射递归地应用某些明确定义的公式来构建校验和。
Apache Commons Lang 库提供了一个 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();
}
哈希码没问题。如果给定的类覆盖了equals
方法,并且按照合同要求覆盖了hashcode
方法,那么就没问题了。按照合同,如果equals
返回true
,则hashcode
必须相同。
或者该类没有覆盖equals
方法。在这种情况下,应用程序的不同执行不能产生相同的对象,因此不存在问题。
唯一的问题是,某些类(甚至来自Java API)违反了equals
的合同。
/*
* Calculate checksum of a File using MD5 algorithm
*/
public static String checkSumApacheCommons(Object obj){
String checksum = DigestUtils.md5Hex(String.valueOf(obj));
return checksum;
}
int checksum(Object o) { return 1;}
的翻译如下:int checksum(Object o){ return 1; }
。 - Tadeusz Kopec for Ukraine