Overriding the .hashCode() method Tutorial

The Object class contains eleven methods; over half of those methods are somehow dependent upon other methods within the Object class to function properly. In a previous tutorial I discussed the relationship between the .wait() method and the .notify() and .notifyAll() methods. One of the most widely used methods, .equals(), shares a special relationship with the .hashcode() method. At this point you should already be familiar with invoking the .equals() method on an object. The purpose of this tutorial is to explain what a hash code is and how to properly override the .hashCode() method.

So what is a hash code? A hash code is a number, and in Java it can simply be any number that fits into the primitive int range of -2147483648 to 2147483647.
What purpose does a hash code serve? The purpose of a hash code is to provide a quick way of locating an object when it is mixed in with a bunch of other objects (clear as mud right???).
Without realizing it, we use hash codes all over the place in everyday life. Imagine that you have a craving for a can of Coca-Cola (Coke) so you head over the grocery store to get one. When you step into the grocery store you are presented with a bunch of stuff for sale. That "stuff" is comprised of thousands of objects; a six-pack of Coke is an object and it is the specific object that you are searching for amongst a sea of other objects.
So where do we begin? We'll just start walking around hoping to stumble across it and we will locate it eventually after some time has elapsed.

Wouldn't it be nice if we knew what aisle Coke was on to narrow our search down? Ah-ha, welcome to the beginning of a hash code. We can look up at the store directory and see that soft drinks are located in aisle 8. We just saved ourselves some time by skipping seven aisles and going directly to aisle 8. 8 is the hash code for our six-pack of Coke object!

Okay we just saved some time and took a shorcut directly to the aisle that Coke is located on, but there are hundreds of objects in this aisle, so now what? Well we know that a can of Coke is red, so we will narrow our search down to only RED items. Our hash code is now 8RED. As we begin walking down the aisle we only pay attention to objects that are red, but can we narrow it down even more? Yes we can, to state the complete obvious a can of Coke has the word "Coke" printed right on it ... go figure! At this point our hash code is now 8REDCOKE and we have narrowed our search results even more. But wait, we are now at a small area that contains not only six-packs but twelve, eighteen, and twenty-four packs as well. Could we make our hash code even larger to something like 8REDCOKE6PACK? The answer is that YES we could, but we will have a numeric overflow when attempting to translate the hash code into a primitive int value!

Say what??? Stick with me here for a second. A hash code is a primitive int number and when we override the .hashCode() method we can calculate the resulting hash code using any formula that we can dream up. For the purposes of this tutorial I am simply going to substitute ASCII values for each character in the hash code above.
8REDCOKE · 8=56, R=82, E=69, D=68, C=67, O=79, K=75, E=69 · 5682696867797569
We have a problem now because our hash code is much too large to fit into a primitive int value, so we have to truncate it to fit. 5682696867797569 will become 568269686 which will fit into a primitive int value. You can probably see the issue is that our hash code is not unique to only a six-pack of Coke. That is OKAY! Hash codes do not have to be unique, that is where the .equals() method takes over to determine which of the tiny number of objects we have left is in fact the one we are searching for.

While we just learned that hash codes do not need to be unique, we should strive to make them as unique as possible. Let's talk about the .hashCode() method in the Object class. How does the JVM generate hash codes in the Object class .hashCode() method? In the Object.java source code file the hashCode() is a native method, meaning it is implemented by the native code in the JVM. Only a select few individuals have access to that source code so I can only make an educated guess based on the documentation. The documentation states: As much as is reasonably practical, the hashCode() method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.) In Java, unlike C and C++, we cannot locate the actual memory address allocated for the object - that is privileged information that the JVM will not give up.

When we override the .hashCode() method we are left to our own devices to come up with a formula for the hash code return value. Does give us carte blanche for doing whatever we want? NO - our formula must adhear to the following rules:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode() method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.
  • If two objects are equal according to the equals(Object) method, then calling the hashCode() method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode() method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
Do you remember how I started this tutorial off with "...over half of those methods are somehow dependent upon other methods within the Object class to function properly.", well this is one of those catch22 situations. You will need to understand the rules for overriding the .equals() method in order to understand overriding the .hashCode() method. On the flip side you will need to understand the rules for overriding the .hashcode() method in order to understand overriding the .equals() method. I chose to begin with the .hashCode() method instead of the .equals() override, but you will need to watch both tutorials to fully understand the relationship



Open the command prompt (CMD - see the Getting Started ) and type in the following commands.

C:\Windows\System32>cd \
C:\>md Java
C:\>cd Java
C:\Java>
C:\Java>md OverridingHashcode
C:\Java>cd OverridingHashcode
C:\Java\OverridingHashcode>Notepad OverridingHashcode.java

Copy and Paste, or type the following code into Notepad and be sure to save the file when you are done.


class OverridingHashcode {
    public static void main(String args[]) {
        CokeSixPack sixPackOne = new CokeSixPack(1.98);
        CokeSixPack sixPackTwo = new CokeSixPack(.99);
        CokeSixPack sixPackThree = sixPackOne;

        System.out.println("sixPackOne hashCode = " + sixPackOne.hashCode()); 
        System.out.println("sixPackTwo hashCode = " + sixPackTwo.hashCode());
        System.out.println("sixPackThree hashCode = " + sixPackThree.hashCode());
        System.out.println();

        CokeTwelvePack twelvePackOne = new CokeTwelvePack(3.48);
        CokeTwelvePack twelvePackTwo = new CokeTwelvePack(1.49);
        System.out.println("twelvePackOne hashCode = " + twelvePackOne.hashCode()); 
        System.out.println("twelvePackTwo hashCode = " + twelvePackTwo.hashCode());
        System.out.println();

        //twelvePackOne.setPrice(4.99);
        //System.out.println("\ntwelvePackOne hashCode = " + twelvePackOne.hashCode()); 

        //for (int i = 0; i < 10; i++) {
        //	System.out.println("twelvePackOne hashCode = " + twelvePackOne.hashCode()); 
        //}

    }
}

class CokeSixPack {
    double price;

    CokeSixPack(double price){
        this.price = price;
    }

    @Override
    public int hashCode() {
        return 568269686;
    }
}

class CokeTwelvePack {
    double price;

    CokeTwelvePack(double price){
        this.price = price;
    }

    @Override
    public int hashCode() {
        return 568269686;
    }
}

/*class CokeSixPack {
    double price;

    CokeSixPack(double price){
        this.price = price;
    }

    void setPrice(double price) {
        this.price = price;
    }

    @Override
    public int hashCode() {
        return (int)(price*41);
        //return (int)(price*41)+(int)System.currentTimeMillis();
    }
}

class CokeTwelvePack {
    double price;

    CokeTwelvePack(double price){
        this.price = price;
    }

    void setPrice(double price) {
        this.price = price;
    }

    @Override
    public int hashCode() {
        return (int)(price*107);
        //return (int)(price*107)+(int)System.currentTimeMillis();
    }
}
*/


Now switch back to the command prompt (CMD) and type in javac OverridingHashcode.java and press Enter.
Now type in java OverridingHashcode and press Enter.


C:\Java\OverridingHashcode>javac OverridingHashcode.java
C:\Java\OverridingHashcode>java OverridingHashcode
sixPackOne hashCode = 56826986
sixPackTwo hashCode = 56826986
sixPackThree hashCode = 56826986

twelvePackOne hashCode = 56826986
twelvePackTwo hashCode = 56826986

see video for further results

Final thoughts

Now that you have a general idea of what a hash code entails, you are ready to watch my next tutorial on overriding the .equals() method. Remember, don't be afraid to just simply return an integer literal if you are not 100% sure that your algorithm will not violate the .hashCode() contract.


Tutorials