当前位置: 首页 > 知识库问答 >
问题:

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

田翰林
2023-03-14

作为一个相对的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不符合其规范。这对我来说是一个非常严重的错误。我是不是完全走错了方向?或者这样的行为是如何被接受的?

共有1个答案

祁乐邦
2023-03-14

您没有重写< 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,则编译会捕获此错误。这就是为什么在可能的情况下始终使用它是一种很好的做法。

 类似资料:
  • 问题内容: 在管道级别,我指定代理和节点(带有标签和自定义工作区)。管道启动时,它将在指定的节点上运行,但是当命中“ build job”时,将选择第一个可用节点。我尝试使用NodeLabel插件,但是那也不起作用。 这是我的: 问题答案: 当您使用Jenkinsfile中的指令时,它告诉Jenkins您想要构建一个完全独立的作业。正是 其他工作 需要指定将要构建的代理。如果这是基于Jenkins

  • 问题内容: 我是Scala的新手,所以我可能对此不太了解,我想知道问题是否出在我的代码上。鉴于Scala文件httpparse,简化为: 使用哪个(URL没关系,这是一个玩笑的示例): 结果总是: 我已经看到有关Java 的Stack Overflow线程 ,以及有关不尝试通过Web访问此DTD 的W3C的System Team Blog条目 。我也将错误隔离到XML.load()方法,据我所知,

  • 问题内容: 我正在使用MySQL,并希望利用该属性。默认的MySQL JDBC实现并不真正尊重它。如果将fetchsize设置为fetchsize,则会分别获取每一行,但是考虑到我要使用fetchSize的原因是,我有足够的数据将内存使用量置于2 G范围内,因此每行必须执行一次查询将永远花费。 相反,我想插入一个可与MySQL一起使用的JDBC实现,并适当考虑取回大小,使我可以将fetchsize

  • 问题内容: 我在进行CSS设计时一直想知道的东西。 是否遵守CSS宽度的小数位数?还是四舍五入? 要么 问题答案: 如果是百分比宽度,那么可以,它是受尊重的。正如Martin所指出的,当您达到小数像素时,事情就会崩溃,但是如果百分比值产生整数像素值(例如,示例中200px的50.5%),您将获得明智的预期行为。 编辑: 我已经更新了示例,以显示小数像素发生了什么(在Chrome中,值被截断了,因此

  • 我正在尝试以一种方式管理日志记录,即最早的存档日志文件一旦达到总累积大小限制或达到最大历史记录限制,就会被删除。在Logback 1.1.7中使用时,滚动文件附加器将继续创建新的存档,尽管超过了设置。 这是日志中的一个bug还是我没有正确配置滚动文件附加器?

  • 问题内容: Javadoc 表示(重点是我): 该操作的行为明确地是不确定的。 对于并行流管道,此操作不能保证遵守流的遇到顺序 ,因为这样做会牺牲并行性的好处。对于任何给定的元素,可以在库选择的任何时间和线程中执行操作。如果操作访问共享状态,则它负责提供所需的同步。 Java 9 Early Access Javadoc中提供了相同的文本。 第一句话(“明确地不确定”)表明(但未明确说明)此方法未