我正在寻找一种解决方案来为任何类型的Java对象生成校验和,对于生成相同对象的应用程序的每次执行,它都保持不变。
我用Object.hashCode()
尝试过,但api说
....从应用程序的一次执行到同一应用程序的另一次执行,这个整数不需要保持一致。
我有类似的问题(为XML文件生成良好的哈希码),我发现最好的解决方案是通过MessageDigest使用MD5,或者如果你需要更快的东西:Fast MD5。请注意,即使Object.hashCode
每次无论如何太短(仅32位)都是相同的,以确保高唯一性。我认为64位是计算良好哈希码的最小值。请注意,MD5生成128位长的哈希码,在这种情况下应该更加需要。
当然要使用MessageDigest
,你需要首先序列化(在你的情况下是marshall)对象。
(或2.字符串 - > md5)
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()); }
我想你应该看看serialization。序列化机制需要解决类似的问题,因此您可以了解它是如何实现的。
但如果你描述了你试图解决的问题,你可能会得到更精确的解决方案。
如果您控制源,则可以实现hashCode(),以便从一个执行到另一个执行保持一致。
您是否希望能够为所有Java对象执行此操作?
在那种情况下hashCode()
不起作用。
对于某些类,hashCode()
有一个更严格的定义,可以保证执行中的平等。例如,String
有一个明确定义的hashCode
实现。类似地,List
和Set
具有明确定义的值,前提是它们包含的所有对象也具有明确定义的值(请注意,一般Collection.hashCode()
不需要对值进行明确定义)。
对于其他类,您必须使用一些明确定义的公式递归地使用反射来构建校验和。
Hashcode没问题。给定的班级覆盖equals
以及合同要求hashcode
。通过契约,如果equals
返回true
哈希码必须是相同的。
或者类不会覆盖equals
。在这种情况下,应用程序的不同执行不能生成相同的对象,因此没有问题。
唯一的问题是某些类(甚至来自Java API)违反了equals
的合同。
如果你正在使用Eclipse IDE,那么它有动作(在Source菜单下)来生成hashcode和equals函数。它允许您在哈希码中选择所需类的属性。这类似于使用已经建议的HashCodeBuilder方法。
或者,您可以将对象流式传输到字节数组并生成MD5。
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();
}