【问题标题】:Wrong implementation pattern for Java equals method [duplicate]Java等于方法的错误实现模式[重复]
【发布时间】:2014-02-19 22:15:10
【问题描述】:

我见过许多 java equals() 方法的实现,它们遵循以下几行:

public boolean equals(Object other){
    if (this == other) 
        return true;

    //this if code
    if (!(other intanceof MyClass))
        return false;
    //ends here

    otherMyClass = (MyClass)other;
    //check all the attribute of this and otherMyClass and return true or false
    //accordingly
}

如果代码存在问题,是否会为 o1.equals(o2) 返回 true(带有 MyClass 的 o1 对象和 MyClasss 的子类的 o2 对象)?在大多数情况下,这不是预期的行为。

other.getClass() != this.getClass() 不是比上面的粗体更好的比较吗?

【问题讨论】:

标签: java subclass equals


【解决方案1】:

o.getClass() != getClass()) 违反里氏替换原则。

引用一位伟人的话:

Liskov 替换原则说,任何重要的属性 一个类型也应该适用于它的子类型,这样任何编写的方法 因为该类型应该同样适用于其子类型。

Effective Java 这本书有更多关于这个主题的细节。

【讨论】:

  • 但是等式必须是可交换的(即if a==b then b==a),在这种情况下可能不是这样。我认为您可以忽略 equals 方法的 LSP...
  • 那么应该有一个liskov替换原则,专门为java equals()定义
  • 如果一个类型的契约定义了一个等价关系,它特别允许不同子类型的实例比较相等,那么每个子类型都必须定义它的 equals 方法来测试那个等价关系而不是其他的。否则,关于 LSP 的任何内容都没有表明必须有可能创建任何特定类的实例,该实例将自身报告为与任何其他对象等效,无论该对象属于同一类还是不同的类。一个对象的getClass()“值”作为比较基础的合法性不亚于其他任何东西。
【解决方案2】:

if (!(other intanceof MyClass)) return false 如果是不同类的实例,将返回 false。

我无法遵循您关于返回 true 的逻辑,因为它无法返回 true。但它可以评估为 true,在这种情况下会执行下一个语句。

【讨论】:

  • 代码中没有“return true”,所以不会。
  • 是的,你是对的 :)
【解决方案3】:

我认为@ChrisForrence (+1) 在评论中引用了最佳答案:Any reason to prefer getClass() over instanceof when generating .equals()?

我想提醒您注意,使用 instanceof 会使 equals() 实现不对称:如果 A 是基类并且 B 扩展 A 而不定义任何其他字段或方法,则可能是 a.equals(b) == true 但 @ 987654325@ 其中aA 的实例,bB 的实例。

【讨论】:

  • 我同意!所以 getClass() 是要走的路(在你清楚地定义了你的系统中对象等价的概念之后)。
  • @Razvan,听起来getClass() 更好。尽管事实上我已经使用instanceofequals() 15 年了......但是从其他情况来看要小心。当您的某些类被框架广泛使用的代理包装时,此技术可能会导致问题。
【解决方案4】:

我实际上在一年前的一次采访中提出了这个问题。我的实现也是使用 instanceof 。我的面试官提到使用 getClass() == other.getClass() 时只有两个论点浮现在我脑海中:

  • 在任何实际情况下,您可能永远不需要子类实例与父对象相等; equals 方法最常见的用途是集合(更具体地说是集合);我在实践中从未遇到过这种情况,但如果这里有人遇到过,请随时将任何仍然适用的非纯理论情况添加为评论(老实说,我很好奇是否有这种情况)
  • 记住equals合约(JavaDoc for Object)的属性:
    • 反身
    • 对称 (*)
    • 传递
    • 一致
    • x.equals(null) 对任何对象 x 返回 false
      • 这已经在其他答案中指出:对称属性可能会与 instanceof 有问题(同样,在实践中,我很少使用包含不同类型元素的集合,但每当我有不同类型时,我从一开始就知道对象实际上是不同的)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-13
    • 2020-10-18
    • 1970-01-01
    • 2021-12-17
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多