About the author

Steven HarmanSteven Harman is a passionate developer who believes that writing great software isn't just a job, its a craft.

ASP.NET MVP

For recent posts and more about me, scroll to the bottom.

Subscribe

  • Subscribe to my feed. via RSS
  • Subscribe via email via email

Jobs

Badges

  • Subtext Project
  • Support Subtext
  • HiddenNetwork.com Banner

[How-To] Override equals() and hashCode()... Part 2.

The Contract

In Part 1 of this series we discussed how to override the equals method for any class the extends from java.lang.Object, why we would want to do so, and a few pitfalls of doing this. In this post we will look at how and why you must also override the hashCode method any time you override an object's equals' method.

So why the hype about hashCode()?

Good question. And I have an answer for you! If you take a look at the Java JDK documentation covering Object.equals you will see that one of the last things mentioned is the following:

Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
I'm not sure why Sun decided to list this point last, but I am glad to see that the C# guys got it right and put the notice at the top of their documentation. But I digress... the reason that this is so important is that the hashCode method is responsible for returning an object's (you guessed it) hash code value as an integer. This hash code value is used by hash based collections such as Hashtable, HashMap, HashSet, etc... for storing, retrieving, sorting, and other data structure operations.

What does that mean?

As compared to the contract inherent to theequals method, the contract defined by the hashCode method is relatively simple and straight forward. There are really only two conditions that must be met:

  1. The hash code value returned by the method must be the same for multiple invocations of the method during the same execution of the application, provided the object is not modified in a way that would affect the equals method.
  2. A corollary to the equals method, The second requirement is that equal objects must produce the same hash code values. However, unequal objects need not produce distinct hash code values, although doing so may improve performance of collections reliant upon the hash values.

To sum it up, equal objects must produce the same hash code value as long as they are equal, however unequal objects do not need to produce distinct hash code values.

How do I implement hashCode

Similar to how we implemented hashCode our hash code calculation must involve all attributes of the class that make contribute to the equality comparison of the class. For our Car example, the following would work:

public int hashCode() 
{
  int hash = 7;
  hash = 31 * hash + 
    (null == this.licensePlate ? 0 : this.licensePlate.hashCode());
  hash = 31 * hash + 
    (null == this.vinNumber ? 0 : this.vinNumber.hashCode());

  return hash;
}

Java provides an implementation of hashCode for built-in classes such as String and other wrapper classes. If you have an int data type that is part of your equals comparison you can simply add, subtract, multiply, or divide it into your hash code value.

Resources

What others are saying.

# re: [How-To] Override equals() and hashCode()... Part 2.
Gravatar Damien Guard
Jun 15, 2006
Great post, I was going to write one myself but you saved me the trouble.

Personally when I'm creating a hashcode though I tend to just XOR the bits together from the various hashcodes.

In the example you show this would be (for C# this time);

public int GetHashCode()
{
int hash = 0;
if (this.licencePlate != null) hash ^= this.licencePlate.GetHashCode();
if (this.vinNumber != null) hash ^= this.vinNumber.GetHashCode();
return hash;
}
# re: [How-To] Override equals() and hashCode()... Part 2.
Gravatar Steve Harman
Jun 15, 2006
Hmm, interesting.

It improves the readability of the code a bit, and still allows us to use the hashCode(s) from the member variables as the base for the new hash.

My only concern (and this is just me being nit-picky) is that while debugging, the result of the XOR isn't as easy for a developer to compute as the arithmetic in the original example is. But again, that is just me being picky... and how often do you really need to step-thru the code for generating a hashCode anyhow?
# re: [How-To] Override equals() and hashCode()... Part 2.
Gravatar Mike Kelly
Apr 24, 2007
The XOR idea sounds good, but I don't think it works all that well as unequal objects can easily have the same hash codes (yeah, I know it's not required that they'd have different codes but it is desirable).

For example, suppose I have a Person class with only two significant fields my hashCode() method would look like (back to Java):

public int hashCode() {
int hash = 0;
if (firstName != null) {
hash ^= firstName.hashCode();
}
if (lastName != null) {
hash ^= lastName.hashCode();
}
return hash;
}

With this sort of implementation two instances of Person, "Kelly Thomas" and "Thomas Kelly" have the same hash code.

All things considered, I think it'd be best to stick with the "traditional" implementation. :)
# re: [How-To] Override equals() and hashCode()... Part 2.
Gravatar Eddie
Apr 16, 2008
My object has a number of instance variables two of which are position and height.
2 objects are considered equal if they have the same position and height.
I have successfully overidden the equals() method but am struggling to override the hashCode() method.
I thought about adding the position and height and returning that as the hash value but that won't work because if we transpose the values for the variables we still get the same hash value.
Any suggestions would be appreciated.
Thanks.
# re: [How-To] Override equals() and hashCode()... Part 2.
Gravatar Steven Harman
Apr 16, 2008
@eddie, You could do something like

public int hashCode()
{
int hash = 7;
hash ^= (31 * _height);
hash ^= (21 * _width);

return hash;
}

That code is very verbose and you can certainly trim it down, but the point is that you have some magic seed numbers in there to make sure that you are weighting the height and width differently so by swapping them you'll change the generated hash.

Does that track?
Comments have been closed on this topic.