Log In

Overriding the hashCode Method in Java

Overriding the hashCode Method in Java
08.07.2024
Reading time: 6 min
Hostman Team
Technical writer

Each object in a program can be represented as an integer. This process is called hashing, and its result is a hash. The hashCode() method in Java generates a hash for objects, making them easier to sort and search.

The generated hash code helps organize quick searches and access to objects in associative arrays or hash tables. This method can be compared to a surjection, meaning every element of set B is the image of at least one element of set A. The following illustration clearly depicts this.

Image1

For all elements in set B, there is at least one corresponding element in set A. The only difference between the hashCode() method and surjection is that any object can be processed by this method.

When using this method, sometimes different objects may have the same hash. For instance, objects C and V are mapped to the same element in the illustration above. These cases are called collisions. The equals() method, closely related to the hashCode() method, helps resolve these collisions.  Another article on Hostman covers more details about equals().

If you plan to use an associative array in your project and use objects as keys, it is recommended to override the hashCode() method for faster and more accurate operation. It is also necessary to override it whenever the equals() method is overridden. We will describe how to correctly override the hashCode() method in Java further in this article.

Requirements for Implementing the hashCode() Method

The declaration of the hashCode() method looks like this:

public int hashCode() {
   // ...
}

To correctly implement this method in Java, the following requirements are defined:

  1. If the hashCode() method is called multiple times on the same object, it must return the same value each time, provided the object's fields are not modified.

  2. If the method is called on two equivalent objects, it must return the same result for both. The equality of such objects can be verified using the equals() method, which should return true if the objects are equal.

  3. If the results returned by the method for two objects are identical, it does not guarantee their equality. However, if they are different, it guarantees that the objects are not equal.

These requirements highlight the importance of using the hashCode() method together with equals() for object comparison. The latter compares objects, while the former indicates if an object's state has changed. This again confirms that when overriding the equals() method, the hashCode() method should also be overridden.

Overriding the hashCode() Method

The first idea that might come to mind for overriding hashCode() in Java is to return a constant.

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

Implementing the override this way is categorically wrong for several reasons:

  • This implementation meets the requirements and will return the same number for two equal objects, but if the state of one changes, its hash code will not change, violating the requirements mentioned above.

  • Such an implementation guarantees collisions.

Given these drawbacks, this approach to overriding the method should be avoided.

There are two correct ways to override the hashCode() method in Java:

  1. Use an existing algorithm for your own implementation.

  2. Use auxiliary methods to generate the hash code.

The first approach involves following these rules for overriding hashCode() in Java:

  • Exclude all redundant fields that are not involved in equals().

  • Choose a base - a starting number for calculating the object's hash code and assign it to a variable total. Developers often use the number 31, but you can choose a different value. Many IDEs generate hash codes using this number.

  • Next, calculate the hash for each remaining field. The table below shows the rules for calculating possible field types:

Field Type

Rule

boolean

(f ? 1 : 0)

char, short, byte, or int

(int) f

float

Float.floatToIntBits(f)

double

Double.doubleToLongBits(f) then (int)(f ^ (f >>> 32))

long

(int)(f ^ (f >>> 32))

Reference to another object

Recursive call to hashCode()

Array

Process each element of the array as a separate field of the object

null

return 0

  • The next rule is to add the calculated hash of each field (let's say it's the variable compute) to the variable total:

total = 31 * total + compute;
  • Finally, return the final value of the variable total after all calculations.

Below is an example of implementing the override for the Staff class, using the rules listed above:

public class Staff {
    private String FCs;
    private String city;
    private int experience;
    private double wage;
    private String department;

    public Staff(String FCs, String city, int experience, double wage, String department) {
        this.FCs = FCs;
        this.city = city;
        this.experience = experience;
        this.wage = wage;
        this.department = department;
    }

    @Override
    public int hashCode() { 
        int total = 31; 
 
        total = total * 31 + (FCs == null ? 0 : FCs.hashCode()); 
        total = total * 31 + (city == null ? 0 : city.hashCode()); 
        total = total * 31 + experience; 
        long lwage = Double.doubleToLongBits(wage); 
        total = total * 31 + (int)(lwage ^ (lwage >>> 32)); 
        total = total * 31 + (department == null ? 0 : department.hashCode()); 
 
        return total; 
    }

    // Overriding equals()
    // ...
}

The @Override annotation before the method declaration checks that the overridden method exists in the parent class. All string fields (FCs, city, and department) are checked for null before calling their hashCode() method to ensure safety from NullPointerException.

The second approach involves using auxiliary methods to generate the hash code, available through the java.util.Objects class starting from Java 8+. An example of this implementation is shown below:

@Override
public int hashCode() {
   return Objects.hash(FCs, city, experience, department);
}

All standard reference data types in Java (String, Integer, Double, etc.) already have correctly overridden equals() and hashCode() methods. Therefore, they can be safely integrated into collections like HashMap, HashSet, and others.

Key Points to Remember

  • A hash is a number generated for an object using hash functions, including hashCode().

  • The Java hashCode() method returns an integer hash code value for a selected object.

  • If you plan to use an associative array in your project and use objects as keys, it is recommended to override the hashCode() method.

  • A well-chosen implementation of the hashCode() method will speed up the performance of associative arrays.

  • When overriding equals(), do not forget to override hashCode(), and vice versa.

  • An incorrect implementation of the Java hashCode() method will result in many collisions.


Share