将对象的哈希码定义为所有类变量哈希码的和,乘,等等是不正确的吗? [英] is it incorrect to define an hashcode of an object as the sum, multiplication, whatever, of all class variables hashcodes?

查看:122
本文介绍了将对象的哈希码定义为所有类变量哈希码的和,乘,等等是不正确的吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有以下课程:

class ABC {
    private int myInt = 1;
    private double myDouble = 2;
    private String myString = "123";
    private SomeRandomClass1 myRandomClass1 = new ...
    private SomeRandomClass2 myRandomClass2 = new ...

    //pseudo code
    public int myHashCode() {
        return 37 *
               myInt.hashcode() *
               myDouble.hashCode() *
               ... *
               myRandomClass.hashcode()
    }
}

这是hashCode的正确实现吗?这不是我通常这样做的方式(我倾向于遵循Effective Java的指导原则),但我总是试图像上面的代码那样做。

Would this be a correct implementation of hashCode? This is not how I usually do it(I tend to follow Effective Java's guide-lines) but I always have the temptation to just do something like the above code.

谢谢

推荐答案

这取决于你所说的正确。假设您正在使用所有相关 equals() -defining字段的 hashCode(),那么是,这是正确的。然而,这样的公式可能不会有良好的分布,因此可能会导致更多的碰撞,这将对性能产生不利影响。

It depends what you mean by "correct". Assuming that you're using the hashCode() of all the relevant equals()-defining fields, then yes, it's "correct". However, such formulas probably will not have a good distribution, and therefore would likely cause more collisions than otherwise, which will have a detrimental effect on performance.

这是一个引用来自 Effective Java 2nd Edition ,第9项:覆盖等于时始终覆盖 hashCode

Here's a quote from Effective Java 2nd Edition, Item 9: Always override hashCode when you override equals


虽然这个项目中的配方产生了相当好的散列函数,但它不会产生最先进的散列函数,也不会产生Java平台库提供了1.6版本的哈希函数。编写这样的哈希函数是一个研究课题,最好留给数学家和计算机科学家。 [...尽管如此,]此项目中描述的技术应该适用于大多数应用程序。

While the recipe in this item yields reasonably good hash functions, it does not yield state-of-the-art hash functions, nor do Java platform libraries provide such hash functions as of release 1.6. Writing such hash functions is a research topic, best left to mathematicians and computer scientists. [...Nonetheless,] the techniques described in this item should be adequate for most applications.

它可能不需要很多数学能力,以评估你提出的哈希函数有多好,但为什么甚至打扰?为什么不遵循在实践中被证明是足够的东西呢?

It may not require a lot of mathematical power to evaluate how good your proposed hash function is, but why even bother? Why not just follow something that has been anecdotally proven to be adequate in practice?


  • 在一个名为 result int 变量中存储一些常量非零值,比如说17, li>
  • 为每个字段计算 int 哈希码 c


    • 如果字段是 boolean ,则计算(f?1:0)

    • 如果字段是字节,char,short,int ,则计算(int) f

    • 如果字段是 long ,则计算(int)( f ^(f>>> 32))

    • 如果字段是 float ,compute Float.floatToIntBits(f)

    • 如果字段是 double ,计算 Double.doubleToLongBits(f),然后将结果 long 哈希,如上所述。

    • 如果该字段是对象引用,并且此类的等于方法com通过递归调用 equals 来削减字段,在字段上递归调用 hashCode 。如果字段的值为 null ,则返回0.

    • 如果字段是数组,则将其视为每个元素都是一个单独的领域。如果数组字段中的每个元素都很重要,则可以使用版本1.5中添加的 Arrays.hashCode 方法之一。

    • Store some constant nonzero value, say 17, in an int variable called result.
    • Compute an int hashcode c for each field:
      • If the field is a boolean, compute (f ? 1 : 0)
      • If the field is a byte, char, short, int, compute (int) f
      • If the field is a long, compute (int) (f ^ (f >>> 32))
      • If the field is a float, compute Float.floatToIntBits(f)
      • If the field is a double, compute Double.doubleToLongBits(f), then hash the resulting long as in above.
      • If the field is an object reference and this class's equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. If the value of the field is null, return 0.
      • If the field is an array, treat it as if each element is a separate field. If every element in an array field is significant, you can use one of the Arrays.hashCode methods added in release 1.5.

      现在,当然这个食谱相当复杂,但幸运的是,你不必每次都重新实现它,这要归功于 java.util.Arrays.hashCode(Object []) (和 com.google.common.base.Objects 提供了方便的vararg变体。)

      Now, of course that recipe is rather complicated, but luckily, you don't have to reimplement it every time, thanks to java.util.Arrays.hashCode(Object[]) (and com.google.common.base.Objects provides a convenient vararg variant).

      @Override public int hashCode() {
          return Arrays.hashCode(new Object[] {
                 myInt,    //auto-boxed
                 myDouble, //auto-boxed
                 myRandomClass,
          });
      }
      



      参见




      • Object.hashCode()

        See also

        • Object.hashCode()


          不是要求如果两个对象根据 equals(java.lang.Object)方法不相等,则调用 hashCode 对两个对象中的每个对象的方法必须产生不同的整数结果。 但是,程序员应该知道为不等对象生成不同的整数结果可能会提高哈希表的性能。

          It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.


        • 这篇关于将对象的哈希码定义为所有类变量哈希码的和,乘,等等是不正确的吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆