Skip to main content

TreeMap.Entry.hashCode() too simplistic?

1 reply [Last post]
jwaldmann
Offline
Joined: 2007-07-25
Points: 0

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

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
alexlamsl
Offline
Joined: 2004-09-02
Points: 0

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]