V6049. Classes that define 'equals' method must also define 'hashCode' method.


The analyzer has detected a user type which overrides the method 'equals', but it doesn't override the method 'hashCode', and vice versa. This can lead to incorrect functioning of the custom type in combination with such collections as HashMap, HashSet and Hashtable, as they actively use 'hashCode' and 'equals' in their work.

Let's consider an example with the usage of HashSet:

public class Employee {

  String name;
  int age;

  public Employee(String name, int age) {
    this.name = name;
    this.age = age;
  }

  public String getName() { return name; }

  public void setName(String name) { this.name = name; }

  public int getAge() { return age; }

  public void setAge(int age) { this.age = age; }

  public String getFullInfo() {
    return this.name + " - " + String.valueOf(age);
  }

  @Override
  public boolean equals(Object obj) {
    if (obj == this)
      return true;
    if (!(obj instanceof Employee))
      return false;
    Employee employee = (Employee) obj;
    return employee.getAge() == this.getAge()
            && employee.getName() == this.getName();
  }
} 

public static void main(String[] args)
{
  HashSet<Employee> employees = new HashSet<>();
  employees.add(new Employee("OLIVER", 25));
  employees.add(new Employee("MUHAMMAD", 54));
  employees.add(new Employee("OLIVER", 25));

  employees.forEach(arg -> System.out.println(arg.getFullInfo()));
}

In the result of the program work, this will be issued on console:

OLIVER - 25
MUHAMMAD - 54
OLIVER - 25 

As we can see, despite the fact that the type 'Employee' overrides the method 'equals', it is not enough. In the course of executing the program we didn't manage to receive an expected result, and the collection contains repeated elements. To eliminate this problem one has to add the overriding of the method 'hashCode' in the declaration of the type 'Employee':

public class Employee {

  ...

  @Override
  public boolean equals(Object obj) {
    if (obj == this)
      return true;
    if (!(obj instanceof Employee))
      return false;
    Employee employee = (Employee) obj;
    return employee.getAge() == this.getAge()
            && employee.getName() == this.getName();
  }

  @Override
  public int hashCode() {
      int result=17;
      result=31*result+age;
      result=31*result+(name!=null ? name.hashCode():0);
      return result;
  }
} 

public static void main(String[] args)
{
  HashSet<Employee> employees = new HashSet<>();
  employees.add(new Employee("OLIVER", 25));
  employees.add(new Employee("MUHAMMAD", 54));
  employees.add(new Employee("OLIVER", 25));

  employees.forEach(arg -> System.out.println(arg.getFullInfo()));
}

Now run the program again. In the result, this will be issued on the console:

MUHAMMAD - 54
OLIVER - 25

We received a correct result: the collection contains only unique elements.


Bugs Found

Checked Projects
336
Collected Errors
12 745