在Java中,我们说我有很长的年和月对列表。像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
我想遍历此列表并为每个条目的这两个值创建一个哈希,以确定我是否已经有一个特定的组合。
通常我会为这样的一个条目创建一个Object,它有两个int成员并覆盖equals和hashcode,将它们全部添加到一个Set中。
我应该如何实现hashCode? strong>
据我记得有效的java,我会写一些类似的东西:
@Override
public int hashCode() {
int hash = year;
hash = 31 * hash + month;
return hash;
}
但我认为,因为月份总是小于一年,在这种情况下我很擅长:
@Override
public int hashCode() {
return year * month;
}
直到4020年,不应发生任何碰撞。
有没有更有效的方法来实现我的目标,你能想到吗? 或者已经太晚了,我的脑袋正在分崩离析?
答案 0 :(得分:3)
只要它满足hashCode
的{{3}},它应该是一个很好的哈希码实现:
- 每当在执行Java应用程序期间多次在同一对象上调用它时,hashCode方法必须始终如一 返回相同的整数,前提是equals中没有使用的信息 对象的比较被修改。不需要保留该整数 从一个应用程序的执行到另一个执行的一致性 相同的申请。
- 如果两个对象根据equals(Object)方法相等,则必须对两个对象中的每一个调用hashCode方法 产生相同的整数结果。
- 如果两个对象根据equals(java.lang.Object)方法不相等,则不需要调用hashCode方法 两个对象中的每一个都必须产生不同的整数结果。 但是,程序员应该意识到产生了不同的 不等对象的整数结果可以提高性能 哈希表。
实施hashCode
方法的另一种方法是调用Objects.hash
:
return Objects.hash(year, month);
答案 1 :(得分:2)
正如您已经提到的Effective Java [1],这是从同一本书中创建一个好的哈希函数的方法:
声明一个名为result的int变量,并将其初始化为对象中第一个重要字段的哈希码c
- 醇>
对于对象中每个剩余的重要字段f,请执行以下操作:
一个。计算字段的int哈希码c:
我。如果该字段是基本类型,则计算Type.hashCode(f),其中Type是与f的类型对应的盒装基元类。
II。如果该字段是一个对象引用,并且该类的equals方法通过递归调用equals来比较该字段,则在该字段上递归调用hashCode。如果需要更复杂的比较,则为该字段计算“规范表示”并在规范表示上调用hashCode。如果字段的值为null,则使用0(或其他常量,但传统的0)。
III。如果该字段是数组,则将其视为每个重要元素都是单独的字段。也就是说,通过递归地应用这些规则来计算每个重要元素的哈希码,并组合每个步骤2.b的值。如果数组没有重要元素,则使用常量,最好不要为0.如果所有元素都很重要,请使用Arrays.hashCode。
湾将步骤2.a中计算的哈希码c组合到结果中,如下所示:
结果= 31 *结果+ c;
- 返回结果。
醇>
将此食谱翻译成您的食谱:
@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)
答案 2 :(得分:0)
您可以查看Java 8的java.time.YearMonth
code(或equivalent class in ThreenTen Backport,Java< = 7)。两者都使用:
public int hashCode() {
return year ^ (month << 27);
}