Java 重写哈希代码和相等时要考虑的数据成员

Java 重写哈希代码和相等时要考虑的数据成员,java,equals,hashcode,Java,Equals,Hashcode,我知道(契约)当覆盖equals时,我们需要覆盖hashcode。 为什么要考虑与计算哈希代码比较相等的相同字段? 它是为了提高性能,避免太多的对象映射到同一个bucket,如下例所示? i、 e.在同一个“日期”创建的所有对象都将映射到同一个bucket,使用equals()方法检查对象是否存在需要时间进行线性比较 如果我的上述说法是正确的,那么除了性能问题之外,下面的代码还有哪些潜在问题。这是我们应该使用equals中使用的相同字段/成员来计算哈希代码的唯一原因吗?请分享。谢谢 class

我知道(契约)当覆盖equals时,我们需要覆盖hashcode。 为什么要考虑与计算哈希代码比较相等的相同字段? 它是为了提高性能,避免太多的对象映射到同一个bucket,如下例所示? i、 e.在同一个“日期”创建的所有对象都将映射到同一个bucket,使用equals()方法检查对象是否存在需要时间进行线性比较

如果我的上述说法是正确的,那么除了性能问题之外,下面的代码还有哪些潜在问题。这是我们应该使用equals中使用的相同字段/成员来计算哈希代码的唯一原因吗?请分享。谢谢

class MyClass {
  int date;
  int pay;
  int id;

  public boolean equals(Object o) {
    //null and same class instance check
    MyClass obj = (MyClass) o;
    return (date == obj.date && pay == obj.pay && id == obj.id);
  }

  public int hashCode() {
    int hash = 7;
    return (31 * hash + date);
  }
}
//请原谅语法错误,我没有使用ide输入


***我的意图是使用equals中的所有字段,并了解为什么hashcode中应该使用相同数量的元素,以及如果只使用很少的元素会发生什么

澄清:
由于只使用“date”来计算hashcode,指针会检查正确的bucket地址(您同意吗?),而且,我得到了该bucket中的项目列表,集合将使用equals迭代检查特定的obj是否存在。我对equals的定义是“所有字段必须相同”。有了这个,我相信我的代码工作得很好,我只发现性能问题。请指出我错在哪里。谢谢你的例子,我建议你只使用
id
来表示相等,并说明它们是覆盖。另外,我喜欢覆盖
toString()


这样,您就可以更新
日期
和/或
支付
,而无需重新创建哈希结构。此外,这也是实例的独特之处。

我在Efficient Java中找到了答案,作者Joshua Bloch,第2版edtn,第49页“不要试图从哈希代码计算中排除对象的重要部分以提高性能”。质量差可能会降低哈希表的性能

所以我的猜测是对的,多个散列将映射到同一个bucket

其他信息:

因为类成员/变量num和data确实参与了 等于方法比较,他们也应该参与 哈希代码的计算但是,这不是强制性的。您可以 使用参与equals方法的变量子集 比较以提高hashCode方法的性能。演出 hashCode方法的实现确实非常重要


我的目的是使用equals中的所有字段,并了解为什么hashcode中应该使用相同数量的元素,以及如果只使用很少的元素会发生什么情况。@davidrun是的,我阅读了您的代码。如果您使用了所有元素,并且您的实例不是不可变的,那么在
HashSet
HashMap
中更改字段将不会像您预期的那样起作用,因为您的实例将更改其相等性,并且hashCode值将与元素分配给的bucket不匹配。Elliott Frish,仅使用“date”为了计算hashcode,指针检查正确的bucket地址(您同意吗?),此外,我得到该bucket中的项目列表,集合将使用equals迭代检查特定的obj是否存在。我对equals的定义是“所有字段必须相同”。有了这一点,我相信我的代码工作得很好,我只发现性能问题。请指出我错在哪里。谢谢。你还必须考虑这个要求(在同一本书的其他地方,Irc中提到),<代码> HASCODE() >与等式一致。基本上,这意味着如果
obj1.equals(obj2)
,则
obj1
obj2
必须具有相同的哈希值。反之亦然;如果
!obj1.equals(obj2)
而且它们的散列值相同,这实际上并没有错,但基于散列的集合的性能会很差。@KevinKrumwiede,是的,我知道这一点,我的目的是了解代码在以下情况下是否失败:如果在equals()比较中使用了“n”个成员,并且我对散列代码使用了“小于n”个成员,我的代码是否会中断或是什么。但它不会中断,但会增加将多个对象映射到同一个bucket的机会,从而降低性能。谢谢
@Override
public boolean equals(Object o) {
  if (o instanceof MyClass) {
    return (id == ((MyClass) o).id);
  }
  return false;
}

@Override
public int hashCode() {
  return id;
}

@Override
public String toString() {
  return String.format("MyClass (id=%d, date=%d, pay=%d)", id, date, pay);
}