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

Java HashSet包含返回false,即使覆盖了equals()和hashCode()

微生弘
2023-03-14

我像这样初始化哈希集:

private HashSet<Rule> ruleTable = new HashSet<Rule>();

我的TcpRule对象(抽象类Rule的子类)的equals()hashCode()方法如下所示:

@Override
public int hashCode() {
    // Ignore source Port for now
    return (this.getSrcPool() + ":" + this.getDstPool() + ":" + this.getProtocol() + ":" + this.dstTcp).hashCode();
}

@Override
public boolean equals(Object obj) {
    if (!(obj instanceof TcpRule))
        return false;
    if (obj == this)
        return true;

    TcpRule r = (TcpRule) obj;
    return (this.getSrcPool().equals(r.getSrcPool()) && this.getDstPool().equals(r.getDstPool()) && this.getProtocol().equals(r.getProtocol()) && this.getSrcTcp() == r.getSrcTcp() && this.getDstTcp() == r.getDstTcp());
}

我甚至编写了一个简单的单元测试,它不会给出任何错误:

@Test
public void equalsTest() {
    Pool srcPool = new Pool("PROXY");
    Pool dstPool = new Pool("WEB");
    int srcTcp = 54321;
    int dstTcp = 80;

    TcpRule r1 = new TcpRule(srcPool, dstPool, srcTcp, dstTcp);
    TcpRule r2 = r1;
    assert r1.equals(r2);

    TcpRule r3 = new TcpRule(srcPool, dstPool, srcTcp, dstTcp);
    TcpRule r4 = new TcpRule(srcPool, dstPool, srcTcp, dstTcp);
    assert r3.equals(r4);
}

@Test
public void hashCodeTest() {
    Pool srcPool = new Pool("PROXY");
    Pool dstPool = new Pool("WEB");
    int srcTcp = 54321;
    int dstTcp = 80;

    TcpRule r1 = new TcpRule(srcPool, dstPool, srcTcp, dstTcp);
    TcpRule r2 = new TcpRule(srcPool, dstPool, srcTcp, dstTcp);
    assert r1.hashCode() == r2.hashCode();

    HashSet<Rule> rules = new HashSet<Rule>();
    rules.add(r1);
    assert rules.contains(r1);

    assert rules.contains(r2);
}

在我的应用程序中,我有一个add()方法,我只需将规则对象添加到哈希集

@Override
public void add(Rule rule) {
    ruleTable.add(rule);
}

在另一种方法中,我检查哈希集中是否存在规则:

    @Override
public boolean isPermittedTcp(IpAddress sourceAddress, IpAddress destinationAddress, short srcTcp, short dstTcp) {
    Pool sourcePool = poolService.getPool(new Host(sourceAddress));
    Pool destinationPool = poolService.getPool(new Host(destinationAddress));
    Rule r = new TcpRule(sourcePool, destinationPool, srcTcp, dstTcp);
    log.info("Checking: " + r.toString());
    log.info("Hash-Code: " + r.hashCode());
    log.info("Hashes in ruleTable:");
    for(Rule rT : ruleTable) {
        log.info("" + rT.hashCode());
    }
    if(ruleTable.contains(r)) {
        log.info("Hash found!");
    } else {
        log.info("Hash not found!");
    }
    return ruleTable.contains(r);
}

日志消息表明规则对象(r.hashCode())的散列是-1313430269,而散列集rT.hashCode()在循环中)中的一个散列也是-1313430269。但是规则表。包含(r)始终返回false。我做错了什么?

我在StackOverflow上发现了类似的问题,但这些问题主要涉及未(正确)覆盖的equals()hashCode()方法。我想我已经正确地实现了这两种方法。


共有3个答案

闾丘霖
2023-03-14

您有一个额外的条件等于this.getSrcTcp()==r.getSrcTcp(),这不是哈希代码的一部分-也许这就是问题所在,哈希代码是相同的,但等于是假的。检查此字段在您比较的值中是否不同。

尽管有评论,我认为这不起作用的原因是因为平等

模拟问题的代码:

import java.util.HashSet;

/**
 * @author u332046
 *
 */
public class HashCodeCollisionTest {
    public static class KeyDemo {
        String id;

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + ((id == null) ? 0 : id.hashCode());
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            /*if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            KeyDemo other = (KeyDemo) obj;
            if (id == null) {
                if (other.id != null)
                    return false;
            } else if (!id.equals(other.id))
                return false;
            return true;*/
            return false;
        }

        public KeyDemo(String id) {
            super();
            this.id = id;
        }
    }

    static HashSet<KeyDemo> set = new HashSet<>();

    public static void main(String[] args) {
        set.add(new KeyDemo("hi"));
        set.add(new KeyDemo("hello"));

        System.out.println(set.contains(new KeyDemo("hi")));
    }
}

这将打印false。取消对equals代码的注释,它将打印true

申屠弘图
2023-03-14

有一些可能性:

  • 规则是可变的,在向set添加规则后,某个键(w.r.t.哈希或等于)字段发生了更改

在这里,我猜你有两个实例,池名称上没有等于或池名称上没有hashCode。

靳金鹏
2023-03-14

你的问题是hashCode()equals()不一致。

您的hashCode()实现基于池的toString(),但是您的equals()使用。等于pool类的()。

更改您的. equals()以比较用于生成哈希代码的字符串。

 类似资料:
  • 我用了这个JPA:检查一个实体对象是否被持久化或不知道我是否持久化或合并我的实体,它看起来像这样: 情况是,即使我编辑了我的实体,它也不会被识别为合并。 这是如何可能的,以及如何使其发挥作用?

  • 我正在尝试使用equals方法与对象进行比较,但它总是返回false

  • 我试图覆盖提到的方法为我的: MyObject: 如何重写hashcode(),equals()和compareTo()方法? 目前我有以下几点: 我读到通过id比较是不够的,这是对象是数据库的持久实体(见这里)。 此类型的所有对象的名称和编号不是唯一的。 那么我应该如何覆盖它呢? 我还需要比较它里面的hashMap吗? 我很困惑。该对象唯一独特的地方是map myMap,它将在生命周期的后期填充

  • 问题内容: 我正在尝试用写入文件后删除文件。这是我用来编写的代码: 我刷新并关闭了流,但是当我尝试删除时,返回。 我删除前检查,看看是否该文件存在,并且:,,一切回归真实。在调用这些方法之后,我尝试返回。 我做错了什么吗? 问题答案: 起作用的把戏很奇怪。事情是,当我以前读取文件的内容时,我使用。阅读后,我关闭了缓冲区。 同时,我切换了语言,现在我正在使用读取内容。同样在完成阅读后,我关闭了流。现

  • 在控制台中获得以下结果: 添加项:null 因此,我希望通过将addedItemName字符串与“null”字符串进行比较来知道何时单击了close按钮。这似乎永远不会奏效,而且让我很沮丧,因为我真的不明白。下面是我做的一些其他测试,以展示我如何尝试各种不同的方法,但仍然不起作用。 假的 假的 因此,基本上,console向我显示,当单击关闭按钮时,addedItemName是“null”,但当我

  • 在阅读了大量文档和文章后,我真的对和方法感到非常困惑。主要是,有各种各样的例子和用法让我太困惑了。 那么,你能澄清一下以下几点吗? 1? 2.如果有一个唯一的键,例如,那么我们应该只使用这个字段吗?或者我们应该将它与组合,如下所示? 3.naturaid怎么样?据我所知,它用于唯一字段,例如,<代码>私有字符串isbn 。它的用途是什么?它是否与方法有关?