这是我应该知道的答案,但我无法回答。考虑以下示例:
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方法都必须产生不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同的整数结果可能会提高哈希表的性能。
那么这是否意味着我的代码确实遵循合同的要点之一?
答案 0 :(得分:1)
好吧,在编写我的问题的过程中,我意识到了答案,并且我不想浪费我所有的辛苦工作,所以我要回答它!如果该问题已经有足够多的重复版本,请随时关闭/删除。
以上示例违反的合同部分是第二个。从hashCode
继承的默认Object
使用对象的内存地址,该地址对于每个对象都是唯一的。但是当equals
被上面的内容覆盖时,现在可以使两个不占用相同空间的对象相等。但是根据合同,他们还必须具有不再匹配的hashCode
。
但到第三个对象,也可能有其他不相等的对象具有相同的hashCode
。因此,即使是非常简单的hashCode
也足以使上面的示例正常工作,例如
@Override
public int hashCode() {
return x + y;
}
当然,如果您更关心性能,最好使用稍微冗长的散列函数,该函数将可能的对象分成更多的存储桶以进行更快的处理。