简体   繁体   English

什么是Java中一年和一个月元组的良好hashCode

[英]What is a good hashCode for a year and month tuple in java

In Java, let's say I have a long list of Year and Month pairs. 在Java中,假设我有一长串的年和月对。 Like 2018:03 with a lot of duplicates. 像2018:03一样,有很多重复项。

Month will always be starting with 1.
Year will always be > Month, starting with 2010
if Month or Year == 0 [not_set], hashcode can return 0 (fine), I ignore them

I want to loop over this list and create a hash from those two values for every entry, to determine if I already have a specific combination. 我想遍历此列表,并为每个条目从这两个值创建一个散列,以确定我是否已经具有特定的组合。

Usually I would create an Object for such an entry, with two int members and override equals and hashcode, adding them all into a Set. 通常,我会为此类条目创建一个Object,该对象具有两个int成员,并覆盖equals和hashcode,并将它们全部添加到Set中。

How should I implement the hashCode? 我应该如何实现hashCode?

As far as I remember from effective java, I would write the something like: 就有效的Java而言,我会这样写:

@Override
public int hashCode() {
    int hash = year;
    hash = 31 * hash + month;
    return hash;
}

But I think, because month will always be lesser than year, in this case I am good with: 但是我认为,因为月份总是小于年份,所以在这种情况下,我很满意:

@Override
public int hashCode() {
    return year * month;
}

until the year 4020, there should not occur any collision. 直到4020年,才不会发生任何碰撞。

Are there any more effective ways to achieve my goal, you can think of? 您能想到的还有什么更有效的方法可以实现我的目标? Or is it too late already and my head is falling apart? 还是为时已晚,我的头崩溃了?

As long as it satisfies the general contract of hashCode , it should be a fine hash code implementation: 只要满足hashCode 的一般约定 ,它就应该是一个很好的哈希码实现:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. 在Java应用程序的执行过程中,只要在同一对象上多次调用它,则hashCode方法必须一致地返回相同的整数,前提是未修改该对象的equals比较中使用的信息。 This integer need not remain consistent from one execution of an application to another execution of the same application. 从一个应用程序的执行到同一应用程序的另一执行,此整数不必保持一致。
  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result. 如果根据equals(Object)方法,两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. 根据equals(java.lang.Object)方法,如果两个对象不相等,则不需要在两个对象中的每个对象上调用hashCode方法必须产生不同的整数结果。 However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables. 但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

Another approach to implement the hashCode method would be to call Objects.hash : 实现hashCode方法的另一种方法是调用Objects.hash

return Objects.hash(year, month);

As you already mentioned Effective Java [1], here is the recipe to make a good hash function from the same book: 正如您已经提到过的Effective Java [1]一样,这是从同一本书中获得良好哈希函数的方法:

  1. Declare an int variable named result, and initialize it to the hash code c for the first significant field in your object 声明一个名为result的int变量,并将其初始化为对象中第一个有效字段的哈希码c

  2. For every remaining significant field f in your object, do the following: 对于对象中每个剩余的有效字段f,执行以下操作:

    a. 一种。 Compute an int hash code c for the field: 计算该字段的int哈希码c:

i. 一世。 If the field is of a primitive type, compute Type.hashCode(f), where Type is the boxed primitive class corresponding to f's type. 如果该字段是原始类型,则计算Type.hashCode(f),其中Type是与f的类型相对应的装箱原始类型。

ii. ii。 If the field is an object reference and this class's equals method compares the field by recursively invoking equals, recursively invoke hashCode on the field. 如果字段是对象引用,并且此类的equals方法通过递归调用equals来比较字段,则在字段上递归调用hashCode。 If a more complex comparison is required, compute a “canonical representation” for this field and invoke hashCode on the canonical representation. 如果需要更复杂的比较,请为此字段计算一个“规范表示”,并在规范表示上调用hashCode。 If the value of the field is null, use 0 (or some other constant, but 0 is traditional). 如果该字段的值为null,则使用0(或其他常数,但是0是传统的)。

iii. iii。 If the field is an array, treat it as if each significant element were a separate field. 如果该字段是数组,则将其视为每个重要元素都是一个单独的字段。 That is, compute a hash code for each significant element by applying these rules recursively, and combine the values per step 2.b. 也就是说,通过递归应用这些规则为每个重要元素计算哈希码,并按照步骤2.b组合值。 If the array has no significant elements, use a constant, preferably not 0. If all elements are significant, use Arrays.hashCode. 如果数组没有有效元素,则使用常量,最好不为0。如果所有元素均有效,则使用Arrays.hashCode。

b. b。 Combine the hash code c computed in step 2.a into result as follows: 将步骤2.a中计算的哈希码c合并为以下结果:

result = 31 * result + c; 结果= 31 *结果+ c;

  1. Return result. 返回结果。

Translating this recipe to yours: 将此食谱翻译为您的食谱:

@Override
public int hashCode() {
  int hash = Integer.hashCode(year);
  hash = 31 * hash + Integer.hashCode(month);
  return hash;
}

[1] Effective Java, Third Edition ( http://www.informit.com/store/effective-java-9780134685991 ) [1]有效的Java,第三版( http://www.informit.com/store/effective-java-9780134685991

You can take a look at Java 8's java.time.YearMonth code (or the equivalent class in ThreenTen Backport , for Java <= 7). 您可以看一下Java 8的java.time.YearMonth代码 (或Java <= 7的java.time.YearMonth等效类 )。 Both use: 两者都使用:

public int hashCode() {
    return year ^ (month << 27);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM