[java] source code with practice article to figure out why rewriting equals must rewrite hashcode

Source code with practice article to figure out why rewriting equals must rewrite hashcode

Introduction

This article will take you from the perspective of source code and practical application cases to explore why rewriting equals must rewrite hashcode.

practice

Consider the following scenario. Now there is a student management system, and each student has four attributes: ID number, name, age and gender.

package com.equalsAndHashCode;

import java.util.Objects;

/**
 * 学生
 *
 * @author ez4sterben
 * @date 2023/07/18
 */
public class Student {
    
    

    private String id;
    private String name;
    private Integer age;
    private String sex;

    @Override
    public String toString() {
    
    
        return "Student{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", sex='" + sex + '\'' +
                '}';
    }

    public Student(String id, String name, Integer age, String sex) {
    
    
        this.id = id;
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    public String getId() {
    
    
        return id;
    }

    public void setId(String id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

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

    public Integer getAge() {
    
    
        return age;
    }

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

    public String getSex() {
    
    
        return sex;
    }

    public void setSex(String sex) {
    
    
        this.sex = sex;
    }
}

In real life, it is inevitable that there will be two people with the same name, age and gender. If we want to distinguish them in the data, we need to use the ID number to distinguish them.

Then we want to judge whether the two students in the student management system are the same student, do we only need to judge whether the ID numbers are the same?

Then let's rewrite the equals method to determine whether two students are the same.

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) {
    
    
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
    
    
            return false;
        }
        Student student = (Student) o;
        return id.equals(student.id);
    }

Write another test class to see if it works.

package com.equalsAndHashCode;

/**
 * 测试
 *
 * @author ez4sterben
 * @date 2023/07/18
 */
public class Test {
    
    
    public static void main(String[] args) {
    
    
        Student student1 = new Student("100000202307181024","李华",1,"女");
        Student student2 = new Student("100000202307181025","张三",1,"男");
        System.out.println(student1.equals(student2));
        
        student2.setId("100000202307181024");
        System.out.println(student1.equals(student2));
    }
}

The result of the operation is as follows:

insert image description here
You can see that our rewritten equals method has taken effect. As long as the ID numbers are different, the two students are different.

At this point, you may think: Why do you need to rewrite the hashcode if the test is successful?

Don't worry, consider the following scenario: Now the teacher needs to store all the students in the data set for easy output viewing.

Seeing this requirement, we can analyze it. Of course, each student in the school is different, so the data structure to be used to store different data should be HashSet.

Next we implement this requirement

    package com.equalsAndHashCode;

    import java.util.HashSet;
    import java.util.Set;

    /**
     * 测试
     *
     * @author ez4sterben
     * @date 2023/07/18
     */
    public class Test {
    
    
        public static void main(String[] args) {
    
    
            Student student1 = new Student("100000202307181024","李华",1,"女");
            Student student2 = new Student("100000202307181025","张三",1,"男");

            Set<Student> students = new HashSet<>();
            
            students.add(student1);
            students.add(student2);

            System.out.println(students);
        }
    }

View the results as follows:

insert image description here

Now we have met the teacher's needs, but now there is a problem. A student wrote the wrong name when submitting information online and submitted data multiple times. But don't worry, we are using HashSet, there should be only one copy of data, and there will be no problem of multiple students with the same id.

Let Zhang San take this responsibility

    package com.equalsAndHashCode;

    import java.util.HashSet;
    import java.util.Set;

    /**
     * 测试
     *
     * @author ez4sterben
     * @date 2023/07/18
     */
    public class Test {
    
    
        public static void main(String[] args) {
    
    
            Student student1 = new Student("100000202307181024","李华",1,"女");
            Student student2 = new Student("100000202307181025","张三",1,"男");
            Student student3 = new Student("100000202307181025","张四",1,"男");

            Set<Student> students = new HashSet<>();

            students.add(student1);
            students.add(student2);
            students.add(student3);

            System.out.println(students);
        }
    }

The result is unexpected

insert image description here
In our HashSet, there are actually two students with the same ID number. And the naming of the same ID number should be judged. Isn't HashSet disorderly and non-repeatable?

Let's analyze it through the source code

Source code analysis

Let's look at the source code of HashSet to see why this happens.

First we call the constructor of HashSet

insert image description here

But his content is to create a new HashMap

insert image description here

It turns out that HashSet is implemented with the help of HashMap . Let's take a look at its add method. You can see the structure of the class through the Structure in the idea

insert image description here
insert image description here

Here we can find that this add method also calls the put method of map. Use the incoming element as Key, PRESENT as Value, and PRESENT is actually an empty object

insert image description here

Let's take a look at the put method

insert image description here
insert image description here

It can be seen from here that HashMap actually uses the hash function to judge the nodes, and this hash function uses the Hash function of the incoming Key

insert image description here

So, if we only rewrite equals without rewriting hashcode, it will not match the expected result.

Next we rewrite the hashcode

    @Override
    public int hashCode() {
    
    
        return Objects.hash(id);
    }

As usual, the ID number is the same.

run again

insert image description here

This meets our expectations. As long as the ID number is the same, the student is considered to already exist.

Guess you like

Origin blog.csdn.net/qq_51383106/article/details/131781193