2

Equals common interview questions

Before starting the chat, let's look at a few common interview questions and see if you can answer them all.

  • 1. What is the difference between equals and ==?
  • 2. Are two objects with equal hashcodes == equal? Is equals equal?
  • 3. If two objects are compared with equals to be equal, are their hashcodes equal?

If we do not rewrite equals and hashcode, then it uses the implementation of the Object method. Let's take a brief look

public boolean equals(Object obj) {
    return (this == obj);
}
public static int hashCode(Object o) {
    return o != null ? o.hashCode() : 0;
}

Why rewrite equals

It can be seen from the above code that when the equals provided by Object is compared, it is not a value comparison, but a memory address comparison. From this we can know that if you want to use equals to compare objects, you must rewrite equals.

What are the problems when rewriting equals without rewriting hashCode

Let's look at the following paragraph first

In every class that covers the equals method, hashCode must be covered. If you don't do this, it violates the general convention of hashCode, which is what is said in the comment above. As a result, this class cannot be combined, so it works normally with the hash collection, which refers to HashMap, HashSet, HashTable, and ConcurrentHashMap.
from Effective Java 3rd Edition

Conclusion: rewrites equals without rewriting hashCode, it will not work with the hash set.

In this case, let's take the HashMap we are most familiar with for demonstration and derivation. We know that the keys in the HashMap cannot be repeated. If you add them repeatedly, the ones added later will overwrite the previous content. Then let's take a look at how HashMap determines the uniqueness of the key.

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Looking at the code, it is found that it determines the storage location in the linked list by calculating the hashCode value of the Map key. Then it can be inferred that if we rewrite equals but not hashCode, there may be a contradiction in element duplication.

Let's demonstrate

public class Employee {

private String name;

private Integer age;

public Employee(String name, Integer age) {
    this.name = name;
    this.age = age;
}

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

/*@Override
public int hashCode() {
    return Objects.hash(name, age);
}*/
}
public static void main(String[] args) {

    Employee employee1 = new Employee("冰峰", 20);
    Employee employee2 = new Employee("冰峰", 22);
    Employee employee3 = new Employee("冰峰", 20);

    HashMap<Employee, Object> map = new HashMap<>();

    map.put(employee1, "1");
    map.put(employee2, "1");
    map.put(employee3, "1");

    System.out.println("equals:" + employee1.equals(employee3));
    System.out.println("hashCode:" + (employee1.hashCode() == employee3.hashCode()));
    System.out.println(JSONObject.toJSONString(map));
}

According to the normal situation, there are only two elements in the map, employee2 and employee3.

execution result

The reason for this problem is that the hashCode is not rewritten. When the map calculates the hash value of the key, objects with the same absolute value are calculated except for inconsistent hash values.


Next we open the annotation code of hashCode to see the execution result

Summarize

If equals is rewritten, hashCode must be rewritten. If it is not rewritten, it will cause conflicts with hash sets (HashMap, HashSet, HashTable, ConcurrentHashMap).


一个程序员的成长
308 声望7.3k 粉丝

日拱一卒,功不唐捐