Java 哈希代码比较问题

Java 哈希代码比较问题,java,hashcode,Java,Hashcode,我有一个对象列表,在我们的例子中称为rule,这个对象本身是一个字段列表,我必须对其进行hashcode比较,因为我们不能在 系统 i、 假设我有两条规则R1和R2以及字段A和B 现在,如果R1中A和B的值分别为7和2 在R2中,分别是3和4,然后是我用来检查重复性的过程 对系统中的规则进行哈希代码比较失败 我使用的方法是 for(Rule rule : rules){ changeableAttrCode=0; fieldCounter=1; attributes = rule.getAt

我有一个对象列表,在我们的例子中称为rule,这个对象本身是一个字段列表,我必须对其进行hashcode比较,因为我们不能在 系统

i、 假设我有两条规则R1和R2以及字段A和B

现在,如果R1中A和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,我们存储所有规则的hashcode

所以,请给我建议更好的方法,这样将来就不会出现这种问题,同时也可以看到系统中规则的双重性


提前感谢

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

对于(11,0),(-1,6)。。。根据当前的算法,我们可以轻松地组成无数个类似的等价类

当然,您不能避免冲突-如果您有足够的实例,哈希冲突是不可避免的。但是,您应该将碰撞的机会降至最低。好的散列算法力求将散列值均匀地分布在广泛的值上。实现这一点的典型方法是为包含n个独立字段的对象生成散列值,该散列值是一个n位数字,其基数足以容纳各个字段的不同散列值

在您的情况下,不应与
字段计数器相乘,而应与素数常量相乘,例如31(这将是您的数字的基数)。并将另一个素数常量添加到结果中,例如17。这样可以更好地分散散列值。(当然,具体基础取决于您的字段可以采用什么样的值-我没有这方面的信息。)

另外,如果您实现了
hashCode
,强烈建议您也实现
equals
——事实上,您应该使用后者来测试相等性


这里有一篇文章是关于。

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

对于(11,0),(-1,6)。。。根据当前的算法,我们可以轻松地组成无数个类似的等价类

当然,您不能避免冲突-如果您有足够的实例,哈希冲突是不可避免的。但是,您应该将碰撞的机会降至最低。好的散列算法力求将散列值均匀地分布在广泛的值上。实现这一点的典型方法是为包含n个独立字段的对象生成散列值,该散列值是一个n位数字,其基数足以容纳各个字段的不同散列值

在您的情况下,不应与
字段计数器相乘,而应与素数常量相乘,例如31(这将是您的数字的基数)。并将另一个素数常量添加到结果中,例如17。这样可以更好地分散散列值。(当然,具体基础取决于您的字段可以采用什么样的值-我没有这方面的信息。)

另外,如果您实现了
hashCode
,强烈建议您也实现
equals
——事实上,您应该使用后者来测试相等性


这是一篇关于的文章。

我不明白你在这里想做什么。对于大多数散列函数场景,冲突是不可避免的,因为要散列的对象远远多于可能的散列值(这是一个鸽子洞原则)

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

一些散列函数在最小化冲突方面比其他函数更好,但这仍然是不可避免的


也就是说,有一些简单的指导原则通常可以提供足够好的哈希函数。Joshua Bloch在其《有效Java第二版》一书中给出了以下内容:

  • 在名为
    result
    int
    变量中存储一些常量非零值,例如17
  • 为每个字段计算一个
    int
    hashcode
    c
    • 如果字段是布尔值,则计算
      (f?1:0)
    • 如果字段是一个
      字节、字符、短字符、int
      ,则计算
      (int)f
    • 如果字段是长的,则计算
      (int)(f^(f>>32))
    • 如果字段是一个
      float
      ,则计算
      float.floatToIntBits(f)
    • 如果该字段是一个
      double
      ,请计算
      double.double到longbits(f)
      ,然后像上面一样对结果的
      long
      进行散列
    • 如果字段是对象引用,并且此类的
      equals
      方法通过递归调用
      equals
      来比较字段,则递归调用字段上的
      hashCode
      。如果该字段的值为
      null
      ,则返回0
    • 如果字段是数组,则将其视为每个元素都是单独的字段。如果数组字段中的每个元素都是重要的,则可以使用1.5版中添加的
      数组.hashCode
      方法之一
  • 将hashcode
    c
    组合成
    result
    ,如下所示:
    result=31*result+c

    • 我不明白你在这里想干什么。对于大多数散列函数场景,冲突是不可避免的,因为要散列的对象远远多于可能的散列值(这是一个鸽子洞原则)

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

      一些散列函数
      1 * 7 + 2 * 2 = 11
      1 * 3 + 2 * 4 = 11