【问题标题】:Why (not how) must an Object conform to the javadoc of equals()?为什么(而不是如何)对象必须符合 equals() 的 javadoc?
【发布时间】:2013-04-28 03:12:17
【问题描述】:

The javadoc of Object.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 是这么说的”。我对此并不满意。我想更深入地了解为什么这些规则存在。有人可以仔细阅读这些规则并举例说明如果违反这些规则会出现什么问题吗?

【问题讨论】:

  • 这是一个奇怪的问题。这样当你在一个对象上调用.equals() 时,你总是知道你得到了什么。如果没有一套规则,您将不会真正知道.equals() 给了您什么。但这似乎相当明显,所以我不太确定您在寻找什么。

标签: java equals


【解决方案1】:

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

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

你可以找到第3章here

【讨论】:

    【解决方案2】:

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

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

    • 自反:如果您尝试将相同的元素放入 Set 两次,它将在集合中出现两次,从而阻止无重复功能发挥作用。
    • 对称:排序功能非常难以预测。
    • 传递性:再说一次,排序功能。
    • 一致:一切都将是不可预测的。
    • Null:插入在诸如Sets 和Maps 之类的东西中毫无意义

    欲了解更多信息,我邀请您查看Wikipedia entry on Equality

    【讨论】:

      【解决方案3】:

      要求

      它是自反的:对于任何非空引用值 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

      【讨论】:

      • 我的代码确实有错误,但您的建议是不必要的。如果 x 和 y 是同一个值,并且 y 和 z 是同一个值,那么 x 和 z 是同一个值。
      • 没有。我向你展示了为什么,从逻辑上讲,equals 应该有这些标准。它使它的行为,最像数学中的=。代码只是为了说明逻辑。
      • 好吧,无论如何,我不觉得我对此有更深的了解。我一直在寻找答案,就像我在@duffymo 链接的 Effective Java 中找到的那样,说“第一个要求只是说一个对象必须等于它自己。很难想象无意中违反了这个要求。如果你要违反它然后将您的类的实例添加到集合中,集合的 contains 方法几乎肯定会说该集合不包含您刚刚添加的实例。”这就是为什么
      【解决方案4】:

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

      如果您的问题确实是针对 equals() 方法而没有其他问题,那么……此方法的覆盖所需的大多数属性源自我们如何在数学和逻辑中使用相等性强>。我想不出一个有用的系统,这些属性不适用。因此,原因是熟悉度和可预测性。

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

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

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

      如果x equals y 不是y equals x 的等效语句,我们将不得不放弃一种非常熟悉且根深蒂固的思维方式来使用Java 编程。 这两个表达式应该执行相同的检查,而不管顺序如何,否则它们并不表示真正的相等,而是其他的东西(某种部分相等)。

      它是可传递的:对于任何非空引用值 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 区分开来,我们最终将不得不使用一些非常尴尬的代码模式。

      【讨论】:

        猜你喜欢
        • 2011-06-30
        • 1970-01-01
        • 2019-07-07
        • 1970-01-01
        • 1970-01-01
        • 2011-02-25
        • 2017-08-11
        • 2019-10-10
        • 1970-01-01
        相关资源
        最近更新 更多