2010-10-06 55 views
8

有时我需要通过组合其多个实例成员的hashCode来实现obj的hashCode()方法。例如,如果组合的obj拥有成员,B和C,我经常看到PPL实现它作为实现hashCode()的首选方式是什么?


int hashCode(){ 
    return 31 * 31 * a.hashCode() + 31 * b.hashCode() + c.hashCode(); 
} 

来自哪里这个神奇的数字31?它是4字节的长度还是只是一个素数?

是否有任何其他的首选/标准方式实现hashCode()?

+0

类似(但不一定重复):http://stackoverflow.com/questions/3613102/why-use-a-prime-number-in-hashcode – 2010-10-06 03:24:13

+0

质量31用于String.hashCode()这使得一个好的素数,因为没有太多可能的角色,但是我倾向于使用更大的素数。因为我只是无耻地引用了布洛赫,所以“有趣”素数的好网站是http://primes.utm.edu/curios/ – 2010-10-06 05:57:58

回答

8

请参阅Effective Java's recipe。这只是最好的来源,请放心。

素数的使用只是为了在不知道域的情况下获得合理的分布。溢出到相同的值将需要一段时间。如果我记得正确,值31是相当随意的。

根据布洛赫(他使用17作为初始值和37作为恒定乘数):

非零初始值被使用(...),所以该散列值通过将初始 影响哈希值(...)为零的字段。如果使用零作为 ,则初始值(...)整体散列值将不受任何此类初始字段的影响,这可能会增加冲突。值17是任意的。
...
选择乘数37是因为它是一个奇素数。如果是偶数并且乘法溢出,则信息将会丢失,因为乘以 等于移位。使用质数的好处不在于明确,但为此目的使用质数是传统的。

+0

CW。 – 2010-10-06 03:15:36

+4

在Effective Java的第二版中,Josh Bloch使用了31而不是37.他解释了这个选择:“31的一个很好的性质是乘法可以被替换为移位和减法以获得更好的性能:'31 * i = =(i << 5) - i'。现代虚拟机自动完成这种优化。“ – ColinD 2010-10-06 03:46:54

2

使用HashCodeBuilder从下议院郎咸平:

public int hashCode() { 
    return HashCodeBuilder.reflectionHashCode(this); 
} 

请参阅如何做到这一点,而无需使用反射API。您可以告诉它要包含哪些字段或要忽略哪些字段。

另请参见EqualsBuilder,用于重写equals方法。

6

一个不错的选择是GuavaObjects.hashCode方法。它需要的任何数量的参数,并创建基于它们的哈希码:

@Override public int hashCode() { 
    return Objects.hashCode(a, b, c); 
} 
0

基本上,你的散列码应该由你的POJO的关键参数。一个例子如下。

public int hashCode() { 
    int hash = 0; 
    if (getRollId() != null) { 
     hash += getRollId().hashCode(); 
    } 
    if (getName() != null) { 
     hash += getName().hashCode(); 
    } 
    return hash == 0 ? System.identityHashCode(this) : hash; 
} 

在上面的例子中,roll id和name是该POJO的关键参数。

如果您仅将这些参数添加到您在同一POJO的Eqauls方法中添加的hashCode方法中,这是一种很好的做法。

1

使用IDE生成它。

0

我相信以下是简单场景的良好实践: 如果您的类包含任何只读成员,那么它们将是生成对象哈希码的理想选择。 但是,如果您的类只包含变异成员,则可以创建一个只读int字段,该字段根据传递给构造函数的非空值获取该值。

相关问题