Before we get to that, let’s talk about equals and hashCode

Equals: Method called to determine whether two objects are equal.

   public boolean equals(Object obj) {
        return (this == obj);
   }
Copy the code

Have a look at the equals method code of Java’s Object class. It’s obvious that this method compares the addresses of two objects


Hascode: I don’t know what this method does, but let’s just say it’s the only code that returns the current object. Can be thought of as the primary key of a database table

public native int hashCode(a);
Copy the code

This method is a local method to call the operating system, the implementation we do not care about him.

So why do we need to rewrite hashCode after overriding equals? The Object source code does not seem to tell… Where are these two methods used in Java?

Looking through the source code, I found that The Java collection framework Map uses this method.

Without further ado, let’s have a look at the code

public V put(K key, V value) {
        return putVal(hash(key), key, value, false.true);
}
Copy the code

Class HashMap class HashMap class HashMap class HashMap Go in and let’s have a lookYou can see that this is where the hashCode() method is used, called by the HashMap key object key! All right, cut the crap and keep jerking off

We all know that the data structure of HashMap in Java is array + linked list + red-black tree. Please refer to the detailed descriptionBlog.csdn.net/zhanglei082…[HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] [HashMap] That is, if the hashCode is different, then the HashMap must create a new Node key-value object. This will execute the following code

So far, the results are largely in. When a HashMap puts a key/value pair, it determines whether the key already exists in the container based on the key’s hashCode and equals methods, overwrites it if it does, and creates a new one if it does. So if we do not override hashCode when overriding equals, the hashCode method will still default to the original method provided by Object, and the hashCode method provided by Object will not return the same value (i.e., each Object will return a different value). This results in each object being a new key in the HashMap.

There is no problem in creating a new key for a different object. Well, if there is such a question, I am not very clear about the description.

Just to make it a little bit more intuitive, there’s a user named Zhang SAN, and I created it for him twice

User user = new User("Zhang");
User user1 = new User("Zhang");
// Generic < user object, age >
Map<User,Integer> map = new HashMap<>();
map.put(user,20);
map.put(user1,21);
Copy the code

After executing the above code, how many key-value pairs should there be in the map? From the code, it is easy to say that there are two key-value pairs, but from the business point of view, this is not right, there should not be two key-value pairs, because John is the same person, Map value is stored in his age, from the business point of view, the same person should not appear twice in the container.

At this point, one might ask, how can Map data structure be used in this way, but it is rarely used in practice.

Right, few people at work are stupid enough to use Map like this. So let’s do it another way

Set<User> users = new HashSet<>();
users.add(new User(0001."Zhang"));
users.add(new User(0001."Zhang"));
Copy the code

We all know that the internal implementation of a HashSet is actually a HashMap, but it takes the keys of the HashMap as the values of the Set. What should be the length of users as a result of this code execution? You don’t have to ask, no one would be stupid enough to say length 2.

Speaking of which, let’s post another piece of code to test it out

public class User {

    private Long userId;

    private String name;

    public User(a){}

    public User(Long userId,String name){
        this.userId = userId;
        this.name = name;
    }

    public Long getUserId(a) {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getName(a) {
        return name;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;
        User user = (User) o;
        return Objects.equals(userId, user.userId) &&
                Objects.equals(name, user.name);
    }
    
    public static void main(String[] args) {
        Set<User> users = new HashSet<>();
        users.add(new User(0001L."Zhang"));
        users.add(new User(0001L."Zhang")); System.out.println(users.size()); }}Copy the code

This code has a User class that overrides equals, but not hashCode, so let’s see

And then let’s add the hashCode() method

public class User {

    private Long userId;

    private String name;

    public User(a){}

    public User(Long userId,String name){
        this.userId = userId;
        this.name = name;
    }

    public Long getUserId(a) {
        return userId;
    }

    public void setUserId(Long userId) {
        this.userId = userId;
    }

    public String getName(a) {
        return name;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;
        User user = (User) o;
        return Objects.equals(userId, user.userId) &&
                Objects.equals(name, user.name);
    }

    @Override
    public int hashCode(a) {
        return Objects.hash(userId, name);
    }

    public static void main(String[] args) {
        Set<User> users = new HashSet<>();
        users.add(new User(0001L."Zhang"));
        users.add(new User(0001L."Zhang")); System.out.println(users.size()); }}Copy the code

As you can see, with the hashCode method added, the HashSet length is 1…

Ah, to be a salt fish coder…