I initialize the HashSet like this:
private HashSet<Rule> ruleTable = new HashSet<Rule>();
The equals()
and hashCode()
methods of my TcpRule
object (sub-class of abstract class Rule
) look like this:
@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());
}
I have even written a simple unit test, which does not give any error:
@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);
}
In my application, I have an add()
method where I simply add a Rule
object to the HashSet
:
@Override
public void add(Rule rule) {
ruleTable.add(rule);
}
In another method, I check if a rule exists in the 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);
}
The log messages indicate that the hash of the Rule
object (r.hashCode()
) is -1313430269
, and that one hash in the HashSet
(rT.hashCode()
in the loop) is also -1313430269
.
But ruleTable.contains(r)
always returns false
. What am I doing wrong?
I have found similar questions on StackOverflow, but these mostly involve the equals()
or hashCode()
methods not being (correctly) overridden. I think I have implemented this two methods correctly.
int
whereas your code usesshort
. Are you sure the objects aren't usingint
s and you are comparing usingshort
s? – FoxtrotRule.equals()
depends on theequals()
forPool
and for whatevergetProtocol()
returns, and we can't see the code for those. (Or for theget*()
methods, for that matter, but I'm assuming those are simplereturn <field>;
getters.) Trim the example down to enough to reproduce the problem in code you can post completely. – RabjohnhashCode()
method. Concatenating strings to calculate a hashcode is more expensive than it needs to be. Read here for other ideas. – Irremovable