java.util.HashSet是否不遵循其规范? - java

作为相对的Java noob,我很困惑地发现以下内容:

Point.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));
            }
        }
    }
}

为什么这令人惊讶?因为我在编写代码以依赖均等性且says之前检查了文档,所以:

如果此集合包含指定的元素,则返回true。更多
形式上,当且仅当此集合包含元素e时,才返回true
这样(o == null?e == null:o.equals(e))

这句话很清楚,它说明只需要平等即可。 f.equals(e)返回true,如输出所示。很明显,集合确实包含元素e,使得o.equals(e),但是contains(o)返回false。

虽然可以理解,哈希集还取决于哈希值相同,这是可以理解的,但是HashSet本身的文档中并未提及这一事实,Set的文档中也未提及任何这种可能性。

因此,HashSet不遵守其规范。对我来说,这似乎是一个非常严重的错误。我在这里完全走错了路吗?或如何接受这种行为?

参考方案

您没有覆盖equals(您正在重载它)。 equals需要接受Object作为参数。

做类似的事情

@Override
public boolean equals(Object o) {
    if (!(o instanceof Point))
        return false;
    Point other = (Point) o;
    return x == other.x && y == other.y;
}

(与Edge相同)

覆盖hashCode时始终覆盖equals也很重要。例如参见Why do I need to override the equals and hashCode methods in Java?

请注意,如果您使用@Override,此错误将被编译器捕获。这就是为什么最好在可能的情况下始终使用它的原因。

java:继承 - java

有哪些替代继承的方法? java大神给出的解决方案 有效的Java:偏重于继承而不是继承。 (这实际上也来自“四人帮”)。他提出的理由是,如果扩展类未明确设计为继承,则继承会引起很多不正常的副作用。例如,对super.someMethod()的任何调用都可以引导您通过未知代码的意外路径。取而代之的是,持有对本来应该扩展的类的引用,然后委托给它。这是与Eric…

Java:BigInteger,如何通过OutputStream编写它 - java

我想将BigInteger写入文件。做这个的最好方式是什么。当然,我想从输入流中读取(使用程序,而不是人工)。我必须使用ObjectOutputStream还是有更好的方法?目的是使用尽可能少的字节。谢谢马丁 参考方案 Java序列化(ObjectOutputStream / ObjectInputStream)是将对象序列化为八位字节序列的一种通用方法。但…

Java-如何将此字符串转换为日期? - java

我从服务器收到此消息,我不明白T和Z的含义,2012-08-24T09:59:59Z将此字符串转换为Date对象的正确SimpleDateFormat模式是什么? java大神给出的解决方案 这是ISO 8601标准。您可以使用SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM…

Java:从类中查找项目名称 - java

仅通过类的实例,如何使用Java反射或类似方法查找项目名称?如果不是,项目名称(我真正想要的是)可以找到程序包名称吗? 参考方案 项目只是IDE使用的简单组织工具,因此项目名称不是类或JVM中包含的信息。要获取软件包,请使用Class#getPackage()。然后,可以调用Package#getName()将包作为您在代码的包声明中看到的String来获取…

JAVA 8具有任何匹配属性的对象的过滤器列表 - java

我的要求是通过匹配任何属性的字符串来过滤对象列表。例如,假设Contact类具有三个属性:街道,城市,电话。我知道java流过滤器是如何工作的,在这里我必须将输入字符串与每个属性进行比较,如下所示:contactList.stream().filter(contact -> contact.getStreet().equals("dubai&…