正负重复Double值引发Java HashCode冲突问题及解决咨询
Double正负值哈希码冲突问题及解决选择
我遇到了一个意外的Double哈希码异常行为:当同一Double值的正负版本在hashCode函数中各出现两次时,生成的哈希码完全相同。示例hashCode实现如下:
public final int hashCode() { int result = ... result = 31 * result + netAmount.hashCode(); result = 31 * result + grossAmount.hashCode(); ... return result; }
通过jshell测试发现,正负460.4的哈希码乘以2后结果一致:
Double.valueOf("460.4").hashCode() = 639279104 Double.valueOf("-460.4").hashCode() = -1508204544 Double.valueOf("460.4").hashCode() * 2 = 1278558208 Double.valueOf("-460.4").hashCode() * 2 = 1278558208
原本以为hashCode函数中每次乘以31能避免该问题,但将函数简化为单行计算后,正负值的结果仍相同:
31 * (123 + Double.valueOf("460.4").hashCode()) + Double.valueOf("460.4").hashCode() = -1017901339 31 * (123 + Double.valueOf("-460.4").hashCode()) + Double.valueOf("-460.4").hashCode() = -1017901339
展开计算式后可知,这是因为32倍哈希码的运算(等效于位移操作)导致正负值的结果一致。请问该如何避免此类哈希冲突?是改用37等其他乘数,还是添加Double符号的哈希码?
补充说明
上述单行计算对应的hashCode函数如下,无论使用正负460.4,结果均相同:
public final int hashCode() { int result = 123; result = 31 * result + Double.valueOf("460.4").hashCode(); result = 31 * result + Double.valueOf("460.4").hashCode(); return result; }
最终决定
我已决定不再使用默认hashCode实现,转而采用MurmurHash等哈希算法,原因是默认hashCode无法保证跨JVM版本或应用重启后的一致性。
内容的提问来源于stack exchange,提问作者Claudio
相关产品推荐
相关产品推荐

