Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

For a HashMap that maps from a custom class, how to make it so that two equivalent keys will map to say value?

Tags:

java

I have a custom class, for example's sake let's say it's tuples without order.

public class UnorderedTuple {  
    Integer i1 = null; Integer i2 = null;

    UnorderedTuple(Integer int1, Integer int2) { i1 = int1; i2 = int2; }

    boolean equals(UnorderedTuple t) { return t.i1 == i1 && t.i2 == t2 || t.i2 == i1 && t.i1 == i2; }
}

Like I said, a dumb example. Now, let's say i have

Map<UnorderedTuple, Integer> m = new HashMap<UnorderedTuple, Integer>();

Ideally, I'd like this functionality:

UnorderedTuple ut1 = new UnorderedTuple(1,2);
UnorderedTuple ut2 = new UnorderedTuple(2,1);

m.put(ut1,2);
m.put(ut2,3);
System.out.println(m.get(ut1)==3); //ideally returns true

Is there something I need to implement or extend such that I can have this functionality? In the same way that if you use 2 different, but equal strings, or Integers, or whatever as a key it will map it properly, but if I implement this as written, it treats ut1 and ut2 separately. Even if I construct ut1 and ut2 identically, it does the same thing.

Thanks for your help.

like image 359
A Question Asker Avatar asked Jan 25 '11 14:01

A Question Asker


2 Answers

You need to override hashCode()... in this case you'd probably do it by XORing the hash codes of all the fields involved, to get the order-independence you want.

You also need to override equals(Object) rather than just implementing equals(UnorderedTuple).

I also note that you're using "==" to compare instances of Integer: don't do that. It will work in the test case you've given due to the rules around boxing, but if you try it with values over 127 you may well run into problems - it's only comparing references rather than values. Call equals to compare values properly.

like image 97
Jon Skeet Avatar answered Oct 04 '22 03:10

Jon Skeet


You need to implement hashCode() in a way that is consistent with equals() (in other words, if a.equals(b) returns true, then a.hashCode() == b.hashCode() must be true as well).

Chapter 3 of Effective Java (free PDF!) has all the nitty-gritty details!

Edit: an you also need to make sure that you're actually implementing equals(Object). In your sample code you only implement equals(UnorderedTuple), which is not the same!

like image 23
Joachim Sauer Avatar answered Oct 04 '22 01:10

Joachim Sauer