Introduction to HashCode

First, let’s see how downloading the top-level Object class interprets the HashCode() method:

Let me separate out the explanation:

Summarized as:

  • Hasdcode values are somewhat stable and return consistent results across calls, and are integers
  • The consistency of the results of the equals method and the hashCode values should be the same
  • Not required, but overrides can improve hash table storage performance (reduce collisions)

What does HashCode do

  • Suppose you define a User object:
package dream.on.sakura.entity;
import lombok.Data;
import lombok.ToString;
import java.util.Objects;
/ * * *@ClassName User * @function[Business function] *@Author lcz * @Date2021/07/12 11:06 * /
@Data@ToString public class User {
	private String name;
	private String phone;
	private int age;
}
Copy the code

Neither hashcode/equals method is overridden;

TestMain code:

import dream.on.sakura.entity.User;

import java.util.HashMap;

/ * * *@ClassName TestMain
 * @function[Test program entry] *@Author lcz
 * @Date2021/07/12 11:06 * /
public class TestMain {
    public static void main(String[] args) {
        User userA = new User();
        userA.setName("ABCDEa123abc");
        System.out.println(userA.hashCode());

        User userB = new User();
        userB.setName("ABCDFB123abc");
        System.out.println(userB.hashCode());

        System.out.println(userA.equals(userB));

        HashMap<User, User> container = new HashMap<>();
        // Add a few
        User userC = new User();
        userC.setName("c");
        User userD = new User();
        userD.setName("d"); container.put(userC, userC); container.put(userD, userD); container.put(userA, userA); container.put(userB, userB); System.out.println(container.size()); System.out.println(container.get(userA)); }}Copy the code

In the code I have carefully designed a case where hashCode values are the same but equals methods are different:

At this point we have just stuffed four data objects into the hashMap, but the structure inside is already like this:

  1. Breakpoint snapshot Data structure in table

  1. More intuitive display of ICONS:

Check the storage status of the hashMap data in debugger state. It can be seen that the compact program of data storage is not ideal, even in four cases of heap pressure.

Rewrite HashCode + equals ()

Overwriting the hashCode method with or without the wrong equals method may result in data overwriting; Here I override an incorrect equals method to simulate data overwriting:

package dream.on.sakura.entity;

import lombok.Data;
import lombok.ToString;

import java.util.Objects;

/ * * *@ClassName User
 * @function[Business function] *@Author lcz
 * @Date2021/07/12 11:06 * /
@Data
@ToString
public class User {
    private String name;
    private String phone;
    private int age;

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

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

    /** * incorrect hashcode method *@param o
     * @return* /
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null|| getClass() ! = o.getClass())return false;
        User user = (User) o;
        returnhashCode() == o.hashCode(); }}Copy the code

The TestMain code does not change:

The debugger looks at the container state of the code before the userB object is placed:

2. State of the container after userB is placed:

The size of the container object is obviously incorrect. In this case, the table stores the following contents:

Summary: Key is the same key as before, but value is long gone

This is because when a HashMap performs a PUT operation, the hashCode value locates the array position; Second, the equals method is executed to determine whether the content is equal.

Equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals equals

Write it here: does it give you a better understanding of why referencing datatypes overrides two methods from the specifics of the underlying storage?

Four, that specific how to rewrite

We can refer to the JDK source code operation method:

Effective Java explains why hashCode is 31 on page 42:

31 is used because it is an odd prime. If the multiplier is even and the multiplication overflows, the information is lost, because multiplying by 2 is equivalent to a shift operation. The benefits of using prime numbers are not obvious, but it is customary to use prime numbers to compute hashing results. 31 has a good performance, which can be achieved by shifting and subtracting instead of multiplication: 31 * I == (I << 5) -i, and modern VMS can automate this optimization. This formula can be derived very easily.

Still have one is above this sentence is I copy somebody else’s!!