![](/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.