当前位置: 首页 > 知识库问答 >
问题:

乘法应该是次优的。为什么在hashcode中使用它?

呼延俊风
2023-03-14

哈希函数是非常有用和多功能的。通常,它们用于将一个空间映射到一个小得多的空间。当然,这意味着两个对象可能哈希到相同的值(碰撞),但这是因为您正在减少空间(鸽子原则)。函数的效率很大程度上取决于散列空间的大小。

@Override
html" target="_blank">public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((email == null) ? 0 : email.hashCode());
    result = prime * result + (int) (id ^ (id >>> 32));
    result = prime * result + ((name == null) ? 0 : name.hashCode());
    return result;
}
  • 我不是问我们为什么要用素数。很明显,如果我们用乘法,我们应该用素数。然而,乘以任何数,即使是素数,也应该比异或次优。这就是为什么所有其他非加密散列函数--以及大多数加密函数--使用异或而不是乘法...
  • 我确实没有任何迹象表明(除了那些众所周知的散列函数)xor会更好。事实上,仅凭它被如此广泛地接受,我怀疑它应该是好的,并且在实践中更好的乘以一个素数和和。我在问为什么这是...
  • Java中的int类型可用于表示从-2147483648到2147483647之间的任何整数。
  • 有时对象的hashcode可能是它的内存地址(这在很多情况下很有意义并且很有效)(如果从例如对象继承)

共有1个答案

东门航
2023-03-14

对此的答案是不同因素的混合:

  • 在现代体系结构上,在给定的指令流水线中,执行乘法和移位所花费的时间最终可能无法整体测量--它更多地与CPU上相关执行单元的可用性有关,而不是与所花费的“原始”时间有关;
  • 在实践中,当在日常编程中与标准集合库集成时,哈希函数正确、“足够好”并且易于在IDE中实现自动化通常比它尽可能完美更重要;-收藏库通常会添加辅助哈希函数和潜在的其他幕后技术,以克服否则很差的哈希函数的一些弱点;
  • 对于可调整大小的集合,一个有效的散列函数的目标是将其散列分散在任意大小的散列表的可用范围内(尽管正如我所说的,它将从内置的次要函数中得到帮助):乘以一个“神奇”常数通常是实现这一点的一种廉价方法(或者,即使乘法比移位要贵一点:考虑到好处,仍然足够便宜);相加而不是异或可能有助于稍微允许这种“雪崩”效应。(在大多数实际情况下,您可能会发现它们同样工作得很好。)
  • 您通常可以假设JIT编译器“知道”等价物,例如移动5位和减去1而不是乘以31。仅仅因为你在源代码中写了“*31”,并不意味着它会字面上编译成乘法指令。(实际上,可能是这样,因为不管您怎么想,在所讨论的体系结构上,乘法指令平均可能“更快”...在这种情况下,通常更好的做法是使您的代码坚持所需的逻辑,并让JIT编译器处理低级优化。)
 类似资料:
  • 问题内容: 我只是想知道为什么在类的方法中使用质数?例如,当使用生成我的方法时,总是使用素数31: 问题答案: 因为您想要乘以的数量以及要插入的存储桶的数量具有正交素数分解。 假设要插入8个桶。如果您要用来乘以的数字是8的倍数,则插入的存储桶将仅由最低有效项(一个根本没有相乘)确定。类似的条目将发生冲突。不适用于哈希函数。 31是一个足够大的素数,因此不可能被它整除(实际上,现代的Java Has

  • 我理解mockito.verify()用于确保使用所需参数调用模拟方法。但我不明白这其中的用意。我经常看到类似这样的测试: 测试验证在调用UserService的createUser方法时是否调用了UserDAO的create方法。看起来很荒唐。如果我改变了UserService的实现,使它不调用UserDAO的方法,那么即使实现是正确的,测试也会失败。 我承认在某些情况下,可能需要验证方法被调用

  • 为什幺应该使用流 在node中,I/O都是异步的,所以在和硬盘以及网络的交互过程中会涉及到传递回调函数的过程。你之前可能会写出这样的代码: var http = require('http'); var fs = require('fs'); var server = http.createServer(function (req, res) { fs.readFile(__dirname

  • 问题内容: 一次又一次,我看到Bash在Stack Overflow上使用了答案,而答案被猛烈抨击了,旨在使用这种“邪恶的”构造。为什么这么邪恶? 如果不能安全使用,我应该怎么用呢? 问题答案: 这个问题比眼前的问题还重要。我们将从显而易见的内容开始:具有执行“脏”数据的潜力。脏数据是指尚未重写为XYZ的任何数据;在我们的例子中,它是未格式化的任何字符串,以确保评估安全。 乍看之下,对数据进行消毒

  • 问题内容: 之间有什么区别: 和 我知道JPanel是GUI组件的容器,但我确实看不到使用它的实用程序。当然,我错了,但我是从Swing开始的,所以…为什么我应该使用JPanel?真正的目的是什么? 问题答案: 为什么我应该使用JPanel? 您可以使用JPanel获得以下一项或多项好处: 将组件分组在一起。 为了更好地组织您的组件。 为了使我们能够使用 多种布局 并组合其效果。(例如,用于数字键

  • 问题内容: 触发服务器调用以获取componentWillMount生命周期方法中的数据是一种不好的做法? 以及为什么最好使用componentDidMount。 问题答案: 更新: componentWillMount将很快被弃用。 引用@Dan Abramov 在 React的未来版本中,我们期望componentWillMount 在某些情况下 会触发多次 ,因此您应该对网络请求使用comp