2

的 javadocObject.equals()解释了正确覆盖该方法所需遵循的规则。它说:

  1. 它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true。
  2. 它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。
  3. 它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true。
  4. 它是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。
  5. 对于任何非空引用值 x,x.equals(null) 应该返回 false。

如果有人问我为什么equals()要遵循这些规则,我能给出的唯一答案是,“因为 javadoc 是这么说的”。我对此并不满意。我想更深入地了解这些规则存在的原因。有人可以仔细阅读这些规则,并举例说明如果违反这些规则会出现什么问题吗?

4

4 回答 4

6

这些是平等如何运作的数学定义。我认为数学是更深层的原因。

Collections API 的设计者 Joshua Bloch 在他的“Effective Java”中详细说明了这些。我建议您阅读该章节和所有其他章节。

您可以在此处找到第 3 章。

于 2013-05-03T16:32:38.217 回答
3

主要原因是有许多类和 API 依赖于正确的功能equals才能正常工作。最常见的用途是在java.util包中,Lists 和Sets 和Maps 等等,但还有很多很多其他的。

通过对 的稳健定义equals,您可以启用排序等功能。我不会给您一个很难做到的“原因”,而是给您一个示例。

  • Reflexive:如果您尝试将相同的元素放入 aSet两次,它将在 set 中两次,从而阻止 no-duplicates 功能起作用。
  • 对称:排序功能将是非常不可预测的。
  • 传递:再次,排序功能。
  • 一致:一切都将是不可预测的。
  • Null:插入在诸如Sets 和Maps之类的东西中毫无意义

欲了解更多信息,我邀请您查看关于平等的维基百科条目

于 2013-05-03T16:35:05.330 回答
2

要求

它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true。

解释

这就是说,一个对象 X 在与它自身比较时应该总是返回 true。这在逻辑上如下。想想“=”运算符。

int x = 1;
int y = 1;
if(x == x) { // We expect this to be true every time }


要求

它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。

解释

嗯,这是=数学中的属性。像这样看:

int x = 1;
int y = 1;
if(x == y) { // This should return true }
if(y == x) { // We expect this to have the same output as the first if }


要求

它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true。

解释

同样,一些代码可以解释原因。

int x = 1;
int y = 1;
int z = 1;

if(y == x && x == z)
{
   // It only logically follows that y == z.
}


要求

它是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。

解释

这是一种自我解释。它只是说它的行为就像一个数学函数。也就是说,对于相同的输入,每次都会产生相同的输出。


要求

对于任何非空引用值 x,x.equals(null) 应该返回 false。

解释

这只是一个达成一致的标准。而且,在逻辑上也站得住脚。要成功调用equals对象的方法,它必须是non-null. 如果是non-null,并且您正在测试是否相等null,则它必须是不相等的,因此false.

于 2013-05-03T16:36:17.253 回答
0

如果您从哲学上问为什么我们应该遵循给定 API 的虚拟方法的任何规则,答案是每个软件都注定存在于一个巨大的生态系统中,如果为该生态系统内的相互作用。如果不是这样,我们将面临兼容性、维护和进步的噩梦。

如果您的问题真的是特定于该equals()方法而不是其他任何问题,那么......此方法的覆盖所需的大多数属性都源自我们如何在数学和逻辑中使用相等性。我想不出一个有用的系统,这些属性不适用。因此,原因是熟悉度和可预测性。

它是自反的:对于任何非空引用值 x,x.equals(x) 应该返回 true。

这几乎是该方法的精髓。equals()如果这不适用,则该方法将没有目的——或者,至少,它应该有另一个名称。

它是对称的:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应该返回 true。

如果x equals y不是与y equals x. 无论顺序如何,这两个表达式都应该执行相同的检查,否则它们并不表示真正的相等,而是其他的东西(某种部分相等)。

它是可传递的:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true 并且 y.equals(z) 返回 true,则 x.equals(z) 应该返回 true。

如果这不是真的,那就意味着这equals()不仅仅是以确定的方式比较两个对象的状态。也许它涉及非确定性行为,或者它可能会在比较中考虑另一个对象的状态或程序状态,这将使它非常不可预测并且比它有用得多。

它是一致的:对于任何非空引用值 x 和 y,x.equals(y) 的多次调用始终返回 true 或始终返回 false,前提是没有修改对象上 equals 比较中使用的信息。

如果这不是真的,那将意味着equals()(根据不遵守上述规定的定义)涉及非确定性的东西。我没有理由想出为什么要在比较中进行非确定性行为。

对于任何非空引用值 x,x.equals(null) 应该返回 false。

这是一个直觉上有意义的约定。一个对象的比较null经常发生,所以这种情况下的行为对那个场合最有用。如果我们无法区分活动对象和null,我们将不得不以一些非常尴尬的代码模式结束。

于 2013-05-03T16:45:08.503 回答