java – 恢复哈希码“sum”
作者:互联网
所以,不是每次都计算哈希码,我想我可以保持一个更新所有更改的整数.想象一下有助于哈希码的属性的setter:
public void setFoo(Foo newFoo){
this.hashCalculator.remove(this.foo.hashCode()); // remove old hash code
this.hashCalculator.add(newFoo.hashCode()); // add new hash code
this.foo = newFoo; // set new foo
}
(我希望我没有做一些愚蠢的事情)我认为这将是简单的数学,但我没有实现它.我认为它与溢出的整数有关,但我不确定.显然我错过了一些东西.该部门的剩余部分应该可以加回到价值中,对吧?
这是我的代码.结果应该是1,但这不是我得到的.
class HashCode
{
public int value = 1;
public void add(int val){
// as suggested by effective java
value = value * 37 + val;
}
public void remove(int val){
value = (value - val) / 37;
}
}
HashCode o = new HashCode();
for(int a = 0; a < 1000; a++){
o.add(a);
}
for(int r = 0; r < 1000; r++){
o.remove(r);
}
System.out.println(o.value); // should be 1
解决方法:
第一:无法正确反转导致整数溢出的操作.基本上问题是您无法知道整数溢出是否在前一个操作中发生过一次,两次甚至更多次.因此,在最后一次哈希计算之前,您无法获得原始值.
第二:哈希计算取决于应用的哈希值的顺序.
((1 * 37 + 0) * 37 + 1) * 37 + 2 = 50692
((1 * 37 + 2) * 37 + 1) * 37 + 0 = 53428
^ ^ ^ the hash values.
由于附加最后一个值的哈希值更改取决于所有先前的哈希值,您不能只更改一个中间哈希值,因此没有(表现良好)方法来消除前一个示例中的1对所有未来计算的影响.
如果您使用1,2,3等测试循环而不是1000开始,这应该是显而易见的.如果没有整数溢出,只有在按照添加它们的相反顺序删除哈希值时,循环才会起作用.这是一种在“现实生活”中应用没有意义的限制. @JB Nizet在his comment写的内容在我看来是正确的.
标签:java,math,integer,integer-overflow 来源: https://codeday.me/bug/20190727/1550875.html