Enthuware Sample - hashCode and equals



我正在做一些来自Enthuware模拟器的示例问题。这是一个示例问题

public class GoodOne
{
   int theval;
   public int hashCode()
   {
      return theval%3;
   }
   public boolean equals(Object obj)
   {
      try{
      // 1 insert code here.
      }catch(Exception e) {
        return false;
      }
   }
}

选项如下

  1. return true;
  2. return this == obj? true : (theval%3 == 0 && ((GoodOne)obj).theval%3==0) ? true :false;
  3. return theval%2 == 0? true :false;
  4. return ( (int)Math.random())*10%3 == 0? true :false; .假设 Math.random(( 返回介于 0.0 和 1.0 之间的双精度值(不包括 1.0(。
  5. return false;

模拟器选择的正确答案是选项-2,并给出了此解释。

这意味着如果对象的theval % 3 0. 此外,如果两个对象被确定为相等,则它们的哈希码 ( theval % 3 ( 将始终相同(零(。所以它满足 哈希代码和等于方法的要求。

要记住的规则是:如果equals()方法返回 true,则 两个对象的hashCode()必须相同。反之亦然 可取但不是必需的。

此外,equals 方法必须遵循以下规则:它应该是 反身:对于任何参考值 x,x.equals(x)应返回 true。 它应该是对称的:对于任何参考值 x 和 y,x.equals(y) 当且仅当y.equals(x)返回 true 时,应返回 true。 它应该 可传递:对于任何参考值 x、y 和 z,如果x.equals(y) 返回 true,y.equals(z)返回 true,则x.equals(z)应该 返回 true。 它应该是一致的:对于任何参考值 x 和 y,多次调用x.equals(y)始终返回 true 或 始终返回 false,前提是在 equals 中使用任何信息 修改对象的比较。 对于任何非空引用 值 x,x.equals(null)应返回 false。

选项 1 是错误的,因为它将导致所有对象 被视为平等,因此hashCode()必须返回相同的 值,但事实并非如此。

选项 2 是正确的,因为 3 的所有倍数的hashCode() 0. 因此,如果我们在 equals() 方法中对所有 3 的倍数返回 true,则将满足条件。如果 对象与自身进行比较。

选项 3 不正确,因为将考虑选项 2 和 6 相等,但它们的哈希代码将不同(2 和 0(。

选项 4 是错误的,因为我们无法确定哪些对象将是 被认为是平等的。

我无法理解它的解释。有人可以详细说明为什么选项 2 是正确的吗在此示例中。谢谢。

选项 2 是正确的,因为 3 的所有倍数的 hashCode(( 都是 0。因此,如果我们在 equals(( 方法中对所有 3 的倍数返回 true,则将满足条件。如果将对象与自身进行比较,它也返回 true。

好吧,我必须说,这是一个可怕的解释,有利于为什么这种选择有效。可能是因为,equals()hashCode()方法本身的实现很糟糕。目前,如果两个对象具有相同的哈希码(在某种程度上(,则 equals() 方法返回 true。让我们再看一下那部分:

return this == obj? true : (theval%3 == 0 && ((GoodOne)obj).theval%3==0) ? true :false;

首先,该表达式可以改进为(尽管这也不是一个好的实现(:

return this == obj? true : theval % 3 == ((GoodOne)obj).theval % 3;

现在theVal % 3只不过是该对象的哈希码。因此,基本上,此方法是根据它们的哈希码判断两个对象相等。(嗯,hashCode()方法也不是良好实现的示例(。

equals()方法的一个大问题是,它无法处理null。我的上帝。我建议停止阅读该资源,您如何命名它 - Enthuware

话虽如此,这种等于方法在与给定的哈希码协作时可以正常工作(前提是,null处理正确(。如何,让我们考虑equals方法的合约:

  • 反身:那很好。 a.theVal % 3 == a.theVal % 3 .
  • 对称:这也很好。对于两个对象ab,如果a.theVal % 3 == b.theVal % 3,则反之亦然。
  • 传递 - 这也很好。 a.theVal % 3 = b.theVal % 3b.theVal % 3 == c.theVal % 3,暗示a.theVal % 3 == c.theVal % 3
  • 一致 - 好吧,如果a.theVal % 3 == b.theVal % 3,那么只要a.thevalb.theVal都没有改变,这将永远是正确的。

现在equals()hashCode()之间的合同来了:

  • 如果两个对象相等,则它们的哈希码必须相等。这当然是正确的,因为您已经根据哈希码判断对象相等。

因此,这解释了第二个选项在这里如何很好。

<小时 />

你应该真正记住的事情:

要记住的非常重要的一点是,您应该使用同一组对象属性来计算用于判断对象相等的哈希码,否则合约将破裂。

例如,如果你的类中还有一个字段,比如 - name ,并且你的hashCode方法更改为:

theVal % 3 * name.hashCode();

但是您没有更改equals()方法。然后,如果两个对象具有相同的theVal值,但名称不同,则根据equals()方法实现,它们将相等,但是鉴于上述hashCode()实现,它们的哈希码将不同。

<小时 />

更好的 equals(( 和 hashCode((?

我说过,给定的hashCode()equals()方法不是一个很好的实现。那么什么可以被认为是一个好的实现。好吧,我建议你通过有效的Java-第9项,这确实深入到这个主题。

如果您使用的是 Eclipse IDE,则可以要求它生成这两个方法。Eclipse 生成了相当好的equals()hashCode()方法的实现。

最新更新