This is the 13th day of my participation in Gwen Challenge

Java objects that compare for equality need to override equals and hashCode, which uses the prime number 31. Why all this?

The problem

Compares whether two objects are equal. For the User object below, it is considered the same object as long as the name and age are equal.

The solution

You need to override the equals and hashCode methods of your objects

public class User {
    private String id;
    private String name;
    private String age;

    public User(a){}public User(String id, String name, String age){
        this.id = id;
        this.name = name;
        this.age = age;
    }

    public String getId(a) {
        return id;
    }

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

    public String getName(a) {
        return name;
    }

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

    public String getAge(a) {
        return age;
    }

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

    @Override
    public String toString(a) {
        return this.id + "" + this.name + "" + this.age;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;// The address is equal
        }

        if(obj == null) {return false;// non-null: for any non-null reference x, x.equals(null) should return false.
        }

        if(obj instanceof User){
            User other = (User) obj;
            // If the fields to be compared are equal, the two objects are equal
            if(equalsStr(this.name, other.name)
                    && equalsStr(this.age, other.age)){
                return true; }}return false;
    }

    private boolean equalsStr(String str1, String str2){
        if(StringUtils.isEmpty(str1) && StringUtils.isEmpty(str2)){
            return true;
        }
        if(! StringUtils.isEmpty(str1) && str1.equals(str2)){return true;
        }
        return false;
    }

    @Override
    public int hashCode(a) {
        int result = 17;
        result = 31 * result + (name == null ? 0 : name.hashCode());
        result = 31 * result + (age == null ? 0 : age.hashCode());
        returnresult; }}Copy the code

validation

@Test
    public void testEqualsObj(a){
        User user1 = new User("1"."xiaoming"."14");
        User user2 = new User("2"."xiaoming"."14");
        System.out.println((user1.equals(user2)));// Print true
    }
Copy the code

Why override equals

Equals (user1 == user2); if (user1 == user2); if (user1 == user2);

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

Why override the hashCode method

If you compare two objects to be equal using equals, you can override the equals method, so why overwrite hashCode

When the equals method is overridden, it is often necessary to override the hashCode method to maintain the normal convention of the hashCode method, which states that equal objects must have equal hash codes. So why is that? Just look at the following example.

The hashCode method of the User object is as follows, without overriding the hashCode method of the parent class

@Override
    public int hashCode(a) {
        return super.hashCode();
    }
Copy the code

Use hashSet

@Test
    public void testHashCodeObj(a){
        User user1 = new User("1"."xiaoming"."14");
        User user2 = new User("2"."xiaoming"."14"); Set< User> userSet =newHashSet< > (a); userSet.add(user1); userSet.add(user2); System.out.println(user1.equals(user2)); System.out.println(user1.hashCode() == user2.hashCode()); }Copy the code

We want two objects that are equal to each other to be treated as equal when we use hashSet. By looking at the Add method of a hashSet, we can see that the add method uses the object’s hashCode method to determine this, so we need to rewrite the hashCode method to achieve the desired effect. After rewriting the hashCode method, execute the above result:

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

Run results respectively to true true so: hashCode is used for quick access hash data, such as using HashSet/HashMap/Hashtable class to store data, can according to store objects of hashCode values to determine whether the same.

How do I rewrite hashCode

Int result; initialize a value, such as 17, for each important field in the class that affects the value of the object and is compared to equals: FiledHashValue = filed. HashCode (); filedHashValue = filed. B. Run result = 31 * result + filedHashValue;

Why use 31

Take a look at the source of the String hashCode method:

/**
     * Returns a hash code for this string. The hash code for a
     * {@code String} object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using {@code int} arithmetic, where {@code s[i]} is the
     * <i>i</i>th character of the string, {@code n} is the length of
     * the string, and {@code ^} indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode(a) {
        int h = hash;
        if (h == 0 && value.length &gt; 0) {
            char val[] = value;

            for (int i = 0; i &lt; value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
Copy the code

You can see from the comment that the hashCode method for an empty string returns 0. And there’s a formula in the comments, so you can see it. String source code also uses 31, and then the Internet says there are two reasons:

Reason one: Fewer product result conflicts

31 is a “medium or small” number of protons, and if you use a smaller prime number like 2, the product will be in a very small range, easily causing hash conflicts. If you pick a prime number above 100, you’ll get a hash that exceeds the maximum range of int, neither of which is appropriate. If you hash code more than 50,000 English words (a combination of two different Unix dictionaries) using constants 31, 33, 37, 39, and 41 as multipliers, each constant yields fewer than seven hash conflicts. These numbers are then considered worthy alternative multipliers for generating hashCode. Therefore, 31 is chosen from 31,33,37,39 and so on.

Cause two: 31 can be optimized by the JVM

The most efficient way to compute in the JVM is to perform bitwise operations: * shift left << : discard the highest bits on the left and complete the zeros on the right (move the data on the left *2). * Right shift >> : Move the >> left data /2 to the power. * Unsigned right shift >>> : Whether the highest bit is 0 or 1, the left side completes 0. So: 31 * I = (I << 5) -i (left 312=62, right 22^5-2=62) – if both sides are equal, the JVM is efficient