作为一个相对的Java新手,我很困惑地发现了以下几点:
点. java:
public class Point {
...
public boolean equals(Point other) {
return x == other.x && y == other.y;
}
...
}
Edge.java:
public class Edge {
public final Point a, b;
...
public boolean equals(Edge other) {
return a.equals(other.a) && b.equals(other.b);
}
...
}
主代码段:私有集blockedEdges
public Program(...) {
...
blockedEdges = new HashSet<Edge>();
for (int i = 0; ...) {
for (int j = 0; ...) {
Point p = new Point(i, j);
for (Point q : p.neighbours()) {
Edge e = new Edge(p, q);
Edge f = new Edge(p, q);
blockedEdges.add(e);
// output for each line is:
// contains e? true; e equals f? true; contains f? false
System.out.println("blocked edge from "+p+"to " + q+
"; contains e? " + blockedEdges.contains(e)+
" e equals f? "+ f.equals(e) +
"; contains f? " + blockedEdges.contains(f));
}
}
}
}
为什么这令人惊讶?因为在我将其编码为依赖平等之前,我检查了留档,它说:
如果该集合包含指定的元素,则返回true。更正式地说,当且仅当这个集合包含元素e,使得(o==null?e==null : o.equals(e))
这句话非常清楚,它指出只需要相等。f.equals(e)返回true,如输出所示。所以很明显,集合确实包含一个元素e,o.equals(e),但包含(o)返回false。
虽然可以理解散列集也依赖于相同的散列值,但是在散列集本身的文档中没有提到这个事实,在集的文档中也没有提到任何这样的可能性。
因此,HashSet不符合其规范。这对我来说是一个非常严重的错误。我是不是完全走错了方向?或者这样的行为是如何被接受的?
您没有重写< code>equals(您正在重载它)。< code>equals需要接受< code>Object作为参数。
做一些像
@Override
public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point other = (Point) o;
return x == other.x && y == other.y;
}
(边缘也一样
)
当您覆盖equals
时,始终覆盖hashCode
也很重要。例如,请参阅为什么我需要覆盖Java中的equals和hashCode方法?
请注意,如果您使用了@Override
,则编译会捕获此错误。这就是为什么在可能的情况下始终使用它是一种很好的做法。