Java hashCode

Java hashCode() method has a close relationship with the equals() method as they complement and are used together. On a high level, the equals method should inspect the relevant data of two instances to determine if they are logically the same object. What internal data the equals() method used should also be used to generate the hashCode() value of a specific object instance. Below are more detailed discussion with code examples about Java hashCode.

Java HashCode Introduction

The hashCode is implemented in the Object class and so it is available in all classes in the Java language, as everything is a descendant of the Object class. Every instance is guaranteed to have a hashCode method, because if the current class does not have it, it can use the default implementation in the Object class - which is based on the internal address of the object converted to integer type. If we are writing a class and it is critical to use this with a Hash Table or some Hash implementation in the Java Collections api, it is highly recommended that we implement the hashCode and equals method of the class. Below is a simple example of a class with name Person that has two properties: firstName and lastName. See code below for illustration.
class Person {
    private String lastName;
    private String firstName;
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());
        result = prime * result + ((lastName == null) ? 0 : lastName.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person other = (Person) obj;
        if (firstName == null) {
            if (other.firstName != null)
                return false;
        } else if (!firstName.equals(other.firstName))
            return false;
        if (lastName == null) {
            if (other.lastName != null)
                return false;
        } else if (!lastName.equals(other.lastName))
            return false;
        return true;
    }
    public String getLastName() {
        return lastName;
    }
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}
Let's assume that when two instance of Person class share the same last name and first name, it means it is the same person. Below are some information what was written in the class above:
  • Since we assume that two person with the same first and last name are the same, we used both properties in the equals method.
  • The first few checking in the equals method are standard when auto generated from Eclipse. It is a good default implementation.
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    
    This checks objects in same address should be the same as it is the same instance. The middle line checks for null and last last lines check if we are comparing instances of the same class. In effect, what we are only comparing logically is firstName and lastName.
  • Since firstName and lastName is critical in equals, we typically want to use them too in the hashCode method. We use the hashCode of individual properties and use some mathematical formula to generate the hashCode.
  • As long as lastName and firstName are not changed, the hashCode should also not change regardless of how many times invoked. Will show more examples on this later.
  • Even if we create separate instances of Person, if they share the same firstName and lastName, those instances should have the same hashCode
  • If two instances of Person with different firstName and lastName, it is not required that the hashCode are different from each other. They could be the same and there should be no problem. This is partly because it is not mathematically possible as the number of possible combination of firstName and lastName is greater than what an integer can represent.

Java HashCode Consistent Returned Value

As long as the data used in the equals method are not altered, we expect the hashCode to return the same value on each call. Consider the code below:
Person personA = new Person();
personA.setFirstName("John");
personA.setLastName("Doe");
System.out.println(personA.hashCode());
System.out.println(personA.hashCode());
System.out.println(personA.hashCode());
Each output will be the same as shown by the result below:
71820560
71820560
71820560

But as soon as we change one of the properties used in the equals method, the hashCode may return a different value. Consider the example shown below:

Person personA = new Person();
personA.setFirstName("John");
personA.setLastName("Doe");
System.out.println(personA.hashCode());
System.out.println(personA.hashCode());
personA.setLastName("Smith");
System.out.println(personA.hashCode());

The first two lines outputs the same value. But as soon as we changed the data on one of the property, the hashCode changes:
71820560
71820560
151755737

Java HashCode Are The Same If They Are Equal

If all the data used in equals are the same for two instances, it means the equals method will return true. And if two instances are equal to each other, the hashCode for both should return the same value. See example below:
Person personA = new Person();
personA.setFirstName("John");
personA.setLastName("Doe");
Person personB = new Person();
personB.setFirstName("John");
personB.setLastName("Doe");
System.out.println(personA.equals(personB));
System.out.println(personA.hashCode());
System.out.println(personB.hashCode());

It outputs the same hashCode as they are equal to each other. Below is the output:

true
71820560
71820560

But if they are not equal to each other, then there is no guarantee if the hashCode will be the same for both. There is high chance that they are different with each other. Consider the code below:
Person personA = new Person();
personA.setFirstName("John");
personA.setLastName("Doe");
Person personB = new Person();
personB.setFirstName("Jane");
personB.setLastName("Smith");
System.out.println(personA.equals(personB));
System.out.println(personA.hashCode());
System.out.println(personB.hashCode());
The output for hashCode is different for the two instances. Below is the output:
false
71820560
151344150