The real reason why overriding the object equals method overrides the hashcode method!

The javaGuide explains why hashcode should be rewritten:

3) Why do you have to override the hashCode method when overriding equals? If two objects are equal, the hashcode must be the same. If the two objects are equal, calling the equals method on the two objects returns true. However, two objects have the same hashcode value, and they are not necessarily equal. Therefore, if the equals method is overridden, the hashcode method must also be overridden. The default behavior of hashCode() is to generate unique values for objects on the heap. If hashCode() is not overridden, the two objects of the class will not be equal in any case (even if they point to the same data)

But I don't quite understand. Two objects have the same code. They are not necessarily equal. So what? Why rewrite hashcode?

After reading other blogs and understanding, I think the main reason for rewriting hashcode is to ensure the characteristics of the equals method, that is, the returned results of equals must be consistent with the comparison results of hashcode

Why do we need such protection?

1. Understand what hashcode does

The default behavior of hashCode() is to generate unique values for objects on the heap. If hashCode() is not overridden, the two objects of the class will not be equal in any case (even if they point to the same data)

2. Understand a process
  • 1. Determine and guarantee the uniqueness of objects. When using set and map, we have the following process to determine the uniqueness of hashcode first

When you add an object to the HashSet, the HashSet will first calculate the hashcode value of the object to determine the location of the object. At the same time, it will also compare with the hashcode values of other added objects. If there is no matching hashcode, the HashSet will assume that the object does not appear repeatedly. However, if an object with the same hashcode value is found, the equals() method will be called to check whether the objects with the same hashcode are really the same. If the two are the same, HashSet will not make its join operation successful. If it is different, it will be hashed to another location. (excerpted from the second edition of my java enlightenment book Head First Java). Why? In this way, we greatly reduce the number of equals and greatly improve the execution speed.

From the above two points, let's analyze the consequences if we don't rewrite hashcode

Let's use a map to see his print results

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
}
/**
     * @see Person
     * @param args
     */
    public static void main(String[] args)
    {
        HashMap<Person, Integer> map = new HashMap<Person, Integer>();

        Person p = new Person("jack",22,"male");
        Person p1 = new Person("jack",22,"male");

        System.out.println("p of hashCode:"+p.hashCode());
        System.out.println("p1 of hashCode:"+p1.hashCode());
        System.out.println(p.equals(p1));
        System.out.println(p == p1);

        map.put(p,888);
        map.put(p1,888);
        map.forEach((key,val)->{
            System.out.println(key);
            System.out.println(val);
        });
    }

p of hashCode:356573597
p1 of hashCode:1735600054
false
false
com.blueskyli.practice.Person@677327b6
888
com.blueskyli.practice.Person@1540e19d
888

You can see that when two objects are used as key values, the hashcode compared is actually the memory address on the heap. If we want to use name for uniqueness, we need to rewrite its equals first

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override public boolean equals(Object obj)
    {
        if(obj instanceof Person){
            Person person = (Person)obj;
            return name.equals(person.name);
        }
        return super.equals(obj);
    }
}

Continue printing the above example,The results are as follows:
The comparison result is:
p of hashCode:356573597
p1 of hashCode:1735600054
true
false
com.blueskyli.practice.Person@677327b6
888
com.blueskyli.practice.Person@1540e19d
888

We found that although we have rewritten equlas, it still sets two objects with the same name value in hashmap

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override public boolean equals(Object obj)
    {
        if(obj instanceof Person){
            Person person = (Person)obj;
            return name.equals(person.name);
        }
        return super.equals(obj);
    }

    @Override public int hashCode()
    {
        return name.hashCode();
    }
}

If we want to make the uniqueness based on name in map or set, we must override hashcode

public class Person
{
    private String name;

    private int age;

    private String sex;

    Person(String name,int age,String sex){
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    @Override public boolean equals(Object obj)
    {
        if(obj instanceof Person){
            Person person = (Person)obj;
            return name.equals(person.name);
        }
        return super.equals(obj);
    }

    @Override public int hashCode()
    {
        return name.hashCode();
    }
}

p of hashCode:3254239
p1 of hashCode:3254239
true
false
com.blueskyli.practice.Person@31a7df
888

Summary:

  • 1. For two objects, the address is compared with = = and the equals method (which can be rewritten as required) shall be used for comparison.
  • 2. Rewrite the equals() method to rewrite the hashCode() method.
  • 3. Generally, equal objects have the same hashCode.
  • 4. The String class overrides the equals and hashCode methods to compare values.
  • 5. Rewrite the hashcode method to perform - comparison when storing data into the HashSet/HashMap/Hashtable (you can refer to the source code for understanding)

Added by ramonekalsaw on Fri, 24 Dec 2021 07:54:39 +0200