![](/img/trans.png)
[英]Java contains() method returns False even though overridden equals() returns True
[英]Java HashSet contains returns false, even with overridden equals() and hashCode()
我像这样初始化 HashSet:
private HashSet<Rule> ruleTable = new HashSet<Rule>();
我的TcpRule
对象(抽象类Rule
子类equals()
的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()
方法,我只需将一个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
,并且HashSet
中的一个哈希值rT.hashCode()
循环中的rT.hashCode()
)也是-1313430269
。 但是ruleTable.contains(r)
总是返回false
。 我究竟做错了什么?
我在 StackOverflow 上发现了类似的问题,但这些问题主要涉及未(正确)覆盖的equals()
或hashCode()
方法。 我想我已经正确地实现了这两种方法。
你的问题是, hashCode()
和equals()
不同意。
您的hashCode()
实现基于池的toString()
,但您的equals()
使用池类的.equals()
。
更改您的.equals()
以比较用于生成哈希码的字符串。
有一些可能性:
Rule
是可变的,在向集合中添加规则后,某些键(wrt 哈希或等于)字段发生了变化;==
io equals
进行equals
比较。 在这里,我猜你有两个Pool
实例,在池名称上没有 equals 或在池名称上没有 hashCode。
你在 equals this.getSrcTcp() == r.getSrcTcp() 中有一个额外的条件,它不是哈希码的一部分——也许这就是问题所在,哈希码是相同的,但等于是假的。 检查此字段在您比较的值中是否不同。
尽管有评论,我认为这不起作用的原因是 equals 和 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
。 取消注释 equals 代码并打印true
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.