我正在做一些来自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;
}
}
}
选项如下
-
return true;
-
return this == obj? true : (theval%3 == 0 && ((GoodOne)obj).theval%3==0) ? true :false;
-
return theval%2 == 0? true :false;
-
return ( (int)Math.random())*10%3 == 0? true :false;
.假设 Math.random(( 返回介于 0.0 和 1.0 之间的双精度值(不包括 1.0(。 -
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
. - 对称:这也很好。对于两个对象
a
和b
,如果a.theVal % 3 == b.theVal % 3
,则反之亦然。 - 传递 - 这也很好。
a.theVal % 3 = b.theVal % 3
和b.theVal % 3 == c.theVal % 3
,暗示a.theVal % 3 == c.theVal % 3
。 - 一致 - 好吧,如果
a.theVal % 3 == b.theVal % 3
,那么只要a.theval
或b.theVal
都没有改变,这将永远是正确的。
现在equals()
和hashCode()
之间的合同来了:
- 如果两个对象相等,则它们的哈希码必须相等。这当然是正确的,因为您已经根据哈希码判断对象相等。
因此,这解释了第二个选项在这里如何很好。
<小时 />你应该真正记住的事情:
要记住的非常重要的一点是,您应该使用同一组对象属性来计算用于判断对象相等的哈希码,否则合约将破裂。
例如,如果你的类中还有一个字段,比如 - name
,并且你的hashCode
方法更改为:
theVal % 3 * name.hashCode();
但是您没有更改equals()
方法。然后,如果两个对象具有相同的theVal
值,但名称不同,则根据equals()
方法实现,它们将相等,但是鉴于上述hashCode()
实现,它们的哈希码将不同。
更好的 equals(( 和 hashCode((?
我说过,给定的hashCode()
和equals()
方法不是一个很好的实现。那么什么可以被认为是一个好的实现。好吧,我建议你通过有效的Java-第9项,这确实深入到这个主题。
如果您使用的是 Eclipse IDE,则可以要求它生成这两个方法。Eclipse 生成了相当好的equals()
和hashCode()
方法的实现。