为什么没有调用我的equals方法?

时间:2019-07-24 19:47:57

标签: java overriding

这是我应该知道的答案,但我无法回答。考虑以下示例:

import java.util.Set;
import java.util.HashSet;

class Main {
  public static void main(String[] args) {
    Set<Point> set = new HashSet<>();
    Point p1 = new Point(1, 1);
    Point p2 = new Point(2, 2);
    Point p3 = new Point(2, 2);
    System.out.println(p1.equals(p2)); // false
    System.out.println(p2.equals(p3)); // true
    set.add(p1);
    set.add(p2);
    System.out.println(set.contains(p3)); // false?
  }
}

class Point {
  int x, y;
  public Point(int x, int y) {
    this.x = x;
    this.y = y;
  }
  @Override
  public boolean equals(Object o) {
    Point p = (Point) o;
    return x == p.x && y == p.y;
  }
}

现在,至少在Eclipse中,当我将鼠标悬停在contains的方法上时,它说“如果此集合包含指定的元素,则返回true。更正式地说,当且仅当该集合包含一个元素e这样的(o==null ? e==null : o.equals(e))。”

现在,我希望自从我在公共类中@Override equals方法以来,当contains方法调用equals时,它将使用 my 版本的equals,而不是它从Object继承的比较内存地址的版本。我还尝试过删除@Override并改为使用public boolean equals(Point p)进行声明,但是会发生相同的问题。

这与我专门使用HashSet的事实有关吗?我以为可能是这样,但是从javadocs中的Object.hashCode来看,合同的三点是:

  • 只要在Java应用程序执行期间在同一个对象上多次调用它,hashCode方法就必须始终返回相同的整数,前提是不修改该对象的equals比较中使用的信息。从一个应用程序的一次执行到同一应用程序的另一次执行,此整数不必保持一致。

  • 如果根据equals(Object)方法两个对象相等,则在两个对象中的每个对象上调用hashCode方法必须产生相同的整数结果。

  • 如果根据equals(java.lang.Object)方法,如果两个对象不相等,则不需要在两个对象中的每一个上调用hashCode方法都必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。

那么这是否意味着我的代码确实遵循合同的要点之一?

1 个答案:

答案 0 :(得分:1)

好吧,在编写我的问题的过程中,我意识到了答案,并且我不想浪费我所有的辛苦工作,所以我要回答它!如果该问题已经有足够多的重复版本,请随时关闭/删除。

以上示例违反的合同部分是第二个。从hashCode继承的默认Object使用对象的内存地址,该地址对于每个对象都是唯一的。但是当equals被上面的内容覆盖时,现在可以使两个不占用相同空间的对象相等。但是根据合同,他们还必须具有不再匹配的hashCode

但到第三个对象,也可能有其他不相等的对象具有相同的hashCode。因此,即使是非常简单的hashCode也足以使上面的示例正常工作,例如

@Override
public int hashCode() {
    return x + y;
}

当然,如果您更关心性能,最好使用稍微冗长的散列函数,该函数将可能的对象分成更多的存储桶以进行更快的处理。