当前位置: 首页 > 面试题库 >

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

伯逸明
2023-03-14
问题内容

假设我有以下课程:

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准则),但是我总是很想做类似上面的代码的诱惑。

谢谢


问题答案:

这取决于您所说的“正确”。假设您正在使用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,
    });
}

也可以看看

  • Object.hashCode()


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



 类似资料:
  • 问题内容: 我有一个实现了hashCode()的向量类。它不是我写的,而是使用2个质数对2个向量分量进行异或运算。这里是: …因为这是来自已建立的Java库,所以我知道它可以正常工作。 然后,我有一个Boundary类,其中包含2个向量:“开始”和“结束”(代表直线的端点)。这两个向量的值是边界的特征。 在这里,我尝试为构成该边界的向量的唯一2元组(起点和终点)创建一个良好的hashCode()。

  • 问题内容: 我正在阅读Java 1.6 API提供的HashMap类的代码,无法完全理解以下操作的需要(位于put和get方法的主体中): 该方法具有以下主体: 通过对提供的哈希码执行位操作,可以有效地重新计算哈希。即使API声明如下,我也无法理解这样做的必要性: 这很关键,因为HashMap使用2的幂的哈希表,否则哈希表在低位无差异时会遇到冲突。 我确实知道键值参数存储在数据结构数组中,并且该数

  • 我用java实现了一个类来模拟有理数,它有两个整数来模拟分子和分母。我需要覆盖Object的hashcode方法,所以相同的数字有相同的hash代码。 我已经这样定义了equals()方法: 关于此: 返回分子*分母是个好方法吗? 等价的有理数(如1/4和2/8)是否应该返回相同的哈希码?

  • 问题内容: 基本类型(例如int)的哈希码是什么? 例如,假设num是一个整数。 问题答案: 对于一个最自然的选择是使用本身。一个更好的问题是,用什么的的,因为它不适合的尺度的哈希码。您的最佳解决方案以及所有相关问题将是有效的Java。

  • 多亏了最近一篇文章中的一些好建议,我才从中实现了PBKDF2https://defuse.ca/php-pbkdf2.htm进入一个小的PHP图像库,我正在建设教自己一些PHP。 我知道您将salt和hash存储在数据库中,然后在用户输入密码时重新构建它们以匹配。我不明白的是,当上面网站上的validate_password函数为同一个密码生成不同的、唯一的salt时,它是如何工作的。 例如,我创

  • 每个人在建构 PHP 应用时终究都会加入用户登录的模块。用户的帐号及密码会被储存在数据库中,在登录时用来验证用户。 在存储密码前正确的 哈希密码 是非常重要的。密码的哈希操作是单向不可逆的,该哈希值是一段固定长度的字符串且无法逆向推算出原始密码。这就代表你可以哈希另一串密码,来比较两者是否是同一个密码,但又无需知道原始的密码。如果你不将密码哈希,那么当未授权的第三者进入你的数据库时,所有用户的帐号