# TreeMap.Entry.hashCode() too simplistic?

jwaldmann
Offline
Joined: 2007-07-25

I am getting a lot of hash collisions in code using Maps (of Maps),
as in the following code (see [1] below) which gives output:

a: {1={2=foo}}
c: {2={1=foo}}
a.hashCode(): 101573
c.hashCode(): 101573
a.equals(c): false

According to the contract, the hashCode of a map is the sum
of the hashCodes of its entries. In this case, there is only one entry.

I think the problem is that TreeMap.Entry.hashCode() uses XOR of key's and value's hash
(see code [2] below). Now XOR is associative and commutative
and therefore any two maps of maps {x = { y = value }} and {y = { x = value }}
will have identical hash code.

I perfectly understand why the Map's hashcode must be built
by an associative and commutative operation from the entries' hashes,
but we should have something more asymmetric (instead of XOR) for the entries themselves?

Best regards, Johannes Waldmann, Leipzig, Germany.

[1] code snippet exhibiting hash collisions:

public static void main (String [] argv) {
Map> a = new TreeMap> ();
Map b = new TreeMap ();
b.put (2, "foo");
a.put (1, b);

Map> c = new TreeMap> ();
Map d = new TreeMap ();
d.put (1, "foo");
c.put (2, d);

System.out.println ("a: " + a);
System.out.println ("c: " + c);
System.out.println ("a.hashCode(): " + a.hashCode());
System.out.println ("c.hashCode(): " + c.hashCode());
System.out.println ("a.equals(c): " + a.equals(c));

}

[2] code snippet from TreeMap.Entry:

public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
}

alexlamsl
Offline
Joined: 2004-09-02

Well simplicity is good in general ;-)

As for your case, simply override TreeMap:
[code]
public class ModifiedHashTreeMap extends TreeMap {
@Override
public int hashCode() {
return ~super.hashCode;
}
}
[/code]