Hashcode比较问题

时间:2010-02-25 10:49:58

标签: java hashcode

我有一个对象的列表,在我们的例子中被称为规则,这个对象本身是一个字段列表,我必须对其进行哈希码比较,因为我们不能在 系统。

即假设我有两个规则R1和R2,字段为A&乙

现在,如果A&的值R1中的B分别为7和2。

在R2中它分别是3和4然后我用来检查两面性的过程 系统中的规则是哈希码比较失败

我使用的方法是

for(Rule rule : rules){
changeableAttrCode=0;

fieldCounter=1;

attributes = rule.getAttributes();

for(RuleField ruleField : attributes){

changeableAttrCode = changeableAttrCode + (fieldCounter * ruleField.getValue().hashCode());

fieldCounter++;

}
parameters = rule.getParameters();

for(RuleField ruleField : parameters){

changeableAttrCode = changeableAttrCode + (fieldCounter * ruleField.getValue().hashCode());

fieldCounter++;

}

changeableAttrCodes.add(changeableAttrCode);

这里是changeableAttrCodes,我们存储所有规则的哈希码。

所以请告诉我更好的方法,以便将来不会出现这种问题,也可以看到系统中的规则错误。

提前致谢

5 个答案:

答案 0 :(得分:5)

hashcode()并不意味着用于检查是否相等。 return 42;hashcode()完全有效的实现。为什么不在规则对象中覆盖equals()(以及hashcode())并使用它来检查两个规则是否相等?您仍然可以使用哈希码来检查需要调查哪些对象,因为两个equal()对象应始终具有相同的哈希码,但这是您可能需要或可能不需要的性能改进,具体取决于您的系统。 / p>

答案 1 :(得分:4)

  • 在类规则中实施hashCodeequals
  • equals的实施必须比较其值。

然后使用HashSet<Rule>并询问if(mySet.contains(newRule))

HashSet + equals implementation 解决了哈希的非唯一性问题。它使用散列进行分类和速度,但最后使用等号来确保具有相同散列的两个规则是否相同。

关于哈希的更多信息:如果您想手动执行,请使用素数sudggestion,并查看字符串哈希码的JDK代码。如果你想做一个干净的实现尝试检索元素的哈希码,制作某种int数组并使用Arrays.hashCode(int [])来获取它们组合的哈希码。

答案 2 :(得分:3)

已更新您的哈希算法未产生良好的哈希值分布 - 它为(7,2)和(3,4)提供相同的值:

1 * 7 + 2 * 2 = 11
1 * 3 + 2 * 4 = 11

它也会为(11,0),(-1,6),...提供相同的值,并且可以基于您当前的算法轻松地组成无数个类似的等价类。

当然你无法避免碰撞 - 如果你有足够的实例,哈希冲突是不可避免的。但是,您应该尽量减少碰撞的机会。良好的散列算法努力在很宽的值范围内均匀地散布散列值。实现此目的的典型方法是为包含 n 独立字段的对象生成哈希值,作为 n -digit数字,其基数足以容纳不同的哈希值对于各个领域。

在您的情况下,您应该乘以素数常数,而不是乘以fieldCounter。 31(这将是你的号码的基础)。并为结果添加另一个素数常数,例如17.这为您提供了更好的散列值。 (当然具体的基础取决于你的领域可以采用什么价值 - 我没有相关信息。)

此外,如果您实施hashCode,强烈建议您实施equals - 实际上,您应该使用后者来测试相等性。

以下是关于implementing hashCode的文章。

答案 3 :(得分:2)

我不明白你在这里要做什么。对于大多数散列函数场景,碰撞是不可避免的,因为有更多的对象要哈希,而不是有可能的哈希值(这是一个鸽子原理)。

通常情况下,两个不同的对象可能具有相同的哈希值。您不能单独依赖哈希函数来消除重复项。

一些散列函数在最小化碰撞方面比其他散列函数更好,但它仍然是不可避免的。


也就是说,有一些简单的指导方针通常会提供足够好的哈希函数。 Joshua Bloch在他的“Effective Java 2nd Edition”一书中给出了以下内容:

  • 将一些常量非零值(例如17)存储在名为int的{​​{1}}变量中。
  • 为每个字段计算result哈希码int
    • 如果字段为c,请计算boolean
    • 如果字段为(f ? 1 : 0),请计算byte, char, short, int
    • 如果字段为(int) f,请计算long
    • 如果字段为(int) (f ^ (f >>> 32)),请计算float
    • 如果该字段为Float.floatToIntBits(f),请计算double,然后对结果Double.doubleToLongBits(f)进行哈希处理,如上所述。
    • 如果该字段是对象引用,并且此类的long方法通过递归调用equals来比较字段,则在该字段上递归调用equals。如果字段的值为hashCode,则返回0.
    • 如果字段是数组,则将其视为每个元素都是单独的字段。如果数组字段中的每个元素都很重要,则可以使用版本1.5中添加的null方法之一。
  • 将哈希码Arrays.hashCode合并到c中,如下所示:result

答案 4 :(得分:0)

我开始写道,你可以通过Perfect Hashing获得你想要的唯一方法。

但后来我想到你说你不能在系统中复制对象这一事实。

根据helios的发人深省的评论进行编辑:

您的解决方案取决于您写下“无法复制规则”时的含义。

如果你的意思是字面上你不能,保证只有一个具有特定值集的规则的实例,那么你的问题是微不足道的:你可以进行身份​​比较,在这种情况下你可以进行身份​​比较使用==。

另一方面,你的意思是不应该出于某种原因(性能),那么你的问题也很简单:只进行价值比较。

考虑到你定义问题的方式,在任何情况下都不应该考虑使用哈希码来代替相等。正如其他人所指出的那样,哈希码本质上会产生冲突(假平等),除非你去Perfect Hashing解决方案,但为什么你会在这种情况下?