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

时间:2015-07-01 13:42:47

标签: java equals contains hashcode hashset

我像这样初始化HashSet:

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

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

@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()方法,我只需在Rule中添加HashSet个对象:

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

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

    @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);
}

日志消息表明Rule对象(r.hashCode())的哈希值为-1313430269,而HashSetrT.hashCode()中的哈希值为-1313430269循环)也是ruleTable.contains(r)。 但false始终返回equals()。我做错了什么?

我在StackOverflow上发现了类似的问题,但这些问题主要涉及未被(正确)覆盖的hashCode()mkvirtualenv myenv --python=`which python3` 方法。我想我已经正确地实现了这两种方法。

3 个答案:

答案 0 :(得分:1)

您的问题是<Collapse {...others} expandIcon={({ isActive }) => isActive ? <IconYouWant /> : <IconYouWant />} > {children} </Collapse> initState 不同意

您的@override void initState() { super.initState(); // Create anonymous function: () async { await _performYourTask(); } (); } 实现基于池的hashCode(),但是您的equals()使用池类的hashCode()

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

答案 1 :(得分:0)

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

尽管有评论,我认为这不起作用的原因是因为等于&amp; hashCode实现不使用相同的字段。

模拟问题的代码:

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。取消注释等号代码并打印true

答案 2 :(得分:0)

有一些可能性:

  • Rule是可变的,在向该规则集添加规则后,某些键(w.r.t.哈希或等于)的字段已更改;
  • 如果两个对象相等,则它们应具有相同的hashCode;
  • 错误,就像在equals中使用==进行比较一样。 equals

在这里,我猜您有两个Pool实例,它们的池名不相等或池名的hashCode不相等。