我已经用Netbeans开发了一段时间的Java,而且有些事情我只是依靠工作而没有真正质疑如何。其中包括自动生成的hashCode()和equals()方法。
equals方法很容易理解,但我觉得hashCode方法有些神秘。我不明白为什么它选择乘数并应用它所做的操作。
import java.util.Arrays;
import java.util.Objects;
public class Foo {
int id;
String bar;
byte[] things;
@Override
public int hashCode() {
int hash = 7;
hash = 89 * hash + this.id;
hash = 89 * hash + Objects.hashCode(this.bar);
hash = 89 * hash + Arrays.hashCode(this.things);
return hash;
}
}
搜索文档,此网站和谷歌搜索“netbeans生成哈希码”之类的内容,似乎没有任何相关内容。有谁在这里熟悉这一代策略是什么以及为什么Netbeans使用它?
修改
谢谢你到目前为止的答案!特别是由于this answer on the linked SO question,我理解现在更充分地使用素数来设计hashCode方法的逻辑。然而,到目前为止我没有真正解决的问题的另一个方面是Netbeans如何以及为什么选择它为其生成的方法所做的素数。 hash
字段和另一个乘数(我的示例中为89
)似乎根据班级的各种因素而有所不同。
例如,如果我向该类添加第二个String
,则hashCode()变为
public int hashCode() {
int hash = 7;
hash = 13 * hash + this.id;
hash = 13 * hash + Objects.hashCode(this.bar);
hash = 13 * hash + Objects.hashCode(this.baz);
hash = 13 * hash + Arrays.hashCode(this.things);
return hash;
}
那么,为什么Netbeans选择这些特定的素数而不是其他任何素数?
答案 0 :(得分:3)
这是一种旨在更好地分配哈希值的优化。 Eclipse也是这样做的。请查看Why use a prime number in hashCode?和Why does Java's hashCode() in String use 31 as a multiplier?。
这绝不是必需的。即使return 0;
足以满足equals / hashcode合约。唯一的原因是基于散列的数据结构在良好的分布式散列值下表现更好。
有人会称之为过早优化。我想它没关系,因为它a)免费(生成)和b)广泛认可(几乎每个IDE都这样做)。
答案 1 :(得分:3)
IBM an article介绍了如何编写自己的equals()
和hashCode()
方法。他们正在做的事情很好,虽然31往往是一个更好的素数因为乘法可以更好地优化。
另请查看how String.hashCode()
works。正是这样,但具有不同的素数和同类型。
答案 2 :(得分:2)
来自Joshua Bloch的 Effective Java 2nd ed。的第9项,要记住的重要一点是在覆盖equals()时始终覆盖hashCode()以确保相等的对象将具有相同的哈希码 - 否则您可能很容易违反此合同。虽然他说最先进的哈希函数是博士研究的主题,但他给出了一个好的通用hashCode的方法,在你的情况下,可能会产生:
@Override
public int hashCode() {
int result = 17;
result = 31 * result + id;
result = 31 * result + bar.hashCode();
result = 31 * result + Arrays.hashCode(things);
return result ;
}
正如@zapl和David Ehrmann所提到的,编译器可以很容易地将31的乘法优化为位移和减1运算,因此如果这很重要,可能会更快一些。