将对象的哈希码定义为所有类变量哈希码的总和,乘积或其他乘积是不正确的吗?

问题描述

这取决于您所说的“正确”。假设您正在使用hashCode()所有相关的equals()-defining字段,那么是的,它是“正确的”。但是,此类公式可能不会具有良好的分布,因此可能导致比其他情况更多的冲突,这将对性能产生不利影响。

这是来自 有效Java 2nd Edition条款 9 的引文:覆盖hashCode时始终覆盖equals

尽管此项目中的配方产生了相当不错的哈希函数,但它没有产生最新的哈希函数,Java平台库也没有提供1.6版以上的哈希函数。编写这样的哈希函数是一个研究主题,数学家和计算机科学家最好去做。[…尽管如此]此项中描述的技术对于大多数应用来说应该是足够的。

评估拟议的哈希函数性能可能不需要很多数学能力,但是为什么还要打扰呢?为什么不只是遵循经实践证明已足够的方法呢?

乔什·布洛赫(Josh Bloch)的食谱

  • 将一个恒定的非零值(例如17)存储在int名为的变量中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字段。如果该字段的值为null,则返回0。
    • 如果该字段是数组,则将其视为每个元素都是一个单独的字段。如果数组字段中的每个元素都很重要,则可以使用Arrays.hashCode版本1.5中添加方法之一。
  • 将哈希码c合并result如下:result = 31 * result + c;

现在,该配方当然很复杂,但是幸运的是,由于java.util.Arrays.hashCode(Object[])(并com.google.common.base.Objects提供了一个方便的vararg变体),您不必每次都重新实现它。

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

也可以看看

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

解决方法

假设我有以下课程:

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的正确实现吗?这不是我通常这样做的方式(我倾向于遵循有效的Java准则),但是我总是很想做类似上面的代码的诱惑。

谢谢

猜你在找的技术问答相关文章

如何检查配对的蓝牙设备是打印机还是扫描仪(Android)
是否允许实体正文进行HTTP DELETE请求?
如何将ZipInputStream转换为InputStream?
java.util.logging Java 8中的变量
PowerMockito.doReturn返回null
Java中的RESTful调用
Swing / Java:如何正确使用getText和setText字符串
特殊字符和重音字符
Android Studio中的ndk.dir错误
错误“找不到主类”