When you create your own key pair object, you should face a few thing.
First, you should be aware of implementing hashCode()
and equals()
. You will need to do this.
Second, when implementing hashCode()
, make sure you understand how it works. The given user example
public int hashCode() {
return this.x ^ this.y;
}
is actually one of the worst implementations you can do. The reason is simple: you have a lot of equal hashes! And the hashCode()
should return int values that tend to be rare, unique at it's best. Use something like this:
public int hashCode() {
return (X << 16) + Y;
}
This is fast and returns unique hashes for keys between -2^16 and 2^16-1 (-65536 to 65535). This fits in almost any case. Very rarely you are out of this bounds.
Third, when implementing equals()
also know what it is used for and be aware of how you create your keys, since they are objects. Often you do unnecessary if statements cause you will always have the same result.
If you create keys like this: map.put(new Key(x,y),V);
you will never compare the references of your keys. Cause everytime you want to acces the map, you will do something like map.get(new Key(x,y));
. Therefore your equals()
does not need a statement like if (this == obj)
. It will never occur.
Instead of if (getClass() != obj.getClass())
in your equals()
better use if (!(obj instanceof this))
. It will be valid even for subclasses.
So the only thing you need to compare is actually X and Y. So the best equals()
implementation in this case would be:
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
So in the end your key class is like this:
public class Key {
public final int X;
public final int Y;
public Key(final int X, final int Y) {
this.X = X;
this.Y = Y;
}
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
public int hashCode() {
return (X << 16) + Y;
}
}
You can give your dimension indices X
and Y
a public access level, due to the fact they are final and do not contain sensitive information. I'm not a 100% sure whether private
access level works correctly in any case when casting the Object
to a Key
.
If you wonder about the finals, I declare anything as final which value is set on instancing and never changes - and therefore is an object constant.