【问题标题】:Implement compareTo in terms of equals and hashcode根据 equals 和 hashcode 实现 compareTo
【发布时间】:2015-12-17 18:53:21
【问题描述】:

与使用equals和hashcode相比,执行实现是不是一个坏主意(可能会有我忽略的后果)?我不关心元素的顺序,我只需要排序是确定性的。这当然是假设我的等号和哈希码是正确的。

这是我的 compareTo 的样子

@Override
public int compareTo(DividendEvent other) {
    final int BEFORE = -1;
    final int EQUAL = 0;
    final int AFTER = 1;

    if(other == null){
        return BEFORE;
    }
    else if (this.equals(other)){
        return EQUAL;
    }
    else if (this.hashCode()>other.hashCode()){
        return AFTER;
    }
    else{
        return BEFORE;
    }
}

【问题讨论】:

  • 您是否实现了hashCode 方法以考虑某种排序?
  • 真的没有比 hashcode 更好的比较属性了吗?
  • 坏主意 - equals 很好,但 hashCode 不能保证也不预期是唯一的,它只是为了“桶”。即使你实现它是唯一的,它也不再是一个好的 hashCode。
  • 没错,但你为什么要做这样的事情呢?这仅对通过它们的 hashCode 排序对象有用......我看不到任何价值
  • 我需要他们订购,但并不真正关心订单是什么。如果我重新创建列表,我要填充这些对象,我需要与之前的值进行比较,因此在比较列表之前需要对它们进行排序。

标签: java collections compare


【解决方案1】:

避免“奇怪的事情”重要的是遵守the contract of compareTo,即:

  • sgn(x.compareTo(y)) == -sgn(y.compareTo(x))
  • (x.compareTo(y)>0 && y.compareTo(z)>0) 暗示 x.compareTo(z)>0
  • x.compareTo(y)==0 意味着 sgn(x.compareTo(z)) == sgn(y.compareTo(z)) 对所有 z

对于不相等但具有相同哈希码的对象,您的实现不会勾选第一个框。

你可以这样修改:

else if (this.equals(other) || this.hashCode() == other.hashCode()){

勾选三个方框。然后,您的实现将变得与 equals 不一致,但除此之外它看起来还不错。

假设您的 hashCode 对于给定对象是常量。

【讨论】:

  • “与equals不一致”意味着两个不同(不相等)的对象可能被排序为相等,这意味着它们在sort()中保持原始顺序。在那种情况下,确定性排序的目标只有在原始顺序是确定性的情况下才是正确的,如果是这样,就不需要所有这些了,所以:仍然不是确定性的。解决方案不可行。
  • 看起来很合理。我将承担碰撞的风险,因为发生碰撞的结果是审计表中有 50%(ish)的机会出现空条目......
【解决方案2】:

有时框架需要您覆盖 .equals() 才能工作,(我在 jsf+ejb 中遇到过这种情况),并且这种类型的实现需要根据对象 ID 进行相等性检查。当您以这种方式实现 compareTo 时,您的“比较”对象的逻辑与此不同,这会导致混乱。

如果这些类是您的域对象并且您没有在其他层中使用它们,那可能没问题。我只是认为 .equals 方法以技术方式表示相等(例如相同的数据库 id),而其他一些方法(如 .identical(),您可以自己实现)以业务逻辑方式表示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-02
    • 1970-01-01
    • 1970-01-01
    • 2017-11-19
    • 1970-01-01
    • 2013-07-22
    相关资源
    最近更新 更多