Honey equals & Hashcode
Ha ha! I put my cards on the table! Ali and meituan’s interviewers both asked me the same question. Are you sure you don’t understand?
Today let’s talk about something simple. This is a common question asked in entry-level development and college recruitment interviews.
-
What should we notice when the key of a HashMap is an object?
-
Why override both equals and HashCode methods?
You have ten seconds to think of your answer… ⌚
Can’t think of it doesn’t matter, read this article after the interview encountered the same question is to send points. 📕
What are the equals and Hashcode methods
We know that all classes in Java inherit from the Object class and that the Object class is the parent of all classes. When a subclass calls a method, if the method has not been overridden, it needs to find the method in the parent class above.
Object class
public boolean equals(Object obj) {
return (this == obj);
}
public native int hashCode(a);
Copy the code
In the Object class, hashCode is a local method that simply gets the address of an Object. Equals compares itself to obj. Here we must first recognize the two methods, one is to fetch the address, one is to compare the address.
Let’s get down to business…
What happens if the object is a Key
To demonstrate this, a little code output is null. Here we consider my a and B to be the same object (key) with the same property. I can get the string hello using hashmap.get (b). But it backfired.
public class NoHashCodeAndEquals {
public static void main(String[] args) {
Object o = new Object();
HashMap<Demo, String> hashMap = new HashMap<>();
Demo a = new Demo("A");
Demo b = new Demo("A");
hashMap.put(a, "hello"); String s = hashMap.get(b); System.out.println(s); }}class Demo {
String key;
Demo(String key) {
this.key = key; }}Copy the code
You may feel ok at a glance, A and B are not the same object! The address must be different! Hold on! What are you talking about? What did I just say? 👆 circle it! 😵 (ps: I almost say meng circle 🤭).
Steady!!
Let’s take a quick look at two lines of HashMap source code and wake up immediately.
- Get hashCode to compute the index of the bucket, store the elements, and it looks like nothing’s wrong but compute the index. Right! Simply call the hashCode of the key to compute a subscript value.
static final int hash(Object key) {
int h;
return (key == null)?0 : (h = key.hashCode()) ^ (h >>> 16);
}
Copy the code
Where is the call to equals() in the HashMap?
- Put method (take JDK1.7 as an example)
public V put(K key, V value) {...int hash = hash(key);
// Determine the bucket subscript
int i = indexFor(hash, table.length);
// Find out if there is already a key-value pair, and if there is, update the key-value pair to value
for(Entry<K,V> e = table[i]; e ! =null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
returnoldValue; }}...// Insert new key-value pairs
addEntry(hash, key, value, i)
return null;
}
Copy the code
- Get method (using JDK1.7 as an example)
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for(Entry<K,V> e = table[indexFor(hash, table.length)]; e ! =null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
Copy the code
As shown above: When a HashMap calls the insert or get method and the hash code corresponding to the value is compared to the hash code in the array, the equals method is used to compare whether the key value is equal.
Combined with the code cases I wrote above, let’s wait and taste again!
Demo a = new Demo("A");
Demo b = new Demo("A");
Copy the code
These two lines of code are defined as two key objects with the same meaning (considered to be the same key), but we know that the values of the hashCode methods of these two keys are different.
Compare keys in a HashMap. Find the hashcode() of the key and compare it to equals(). If equals() is not equal, they are not equal.
- If you override hashCode () instead of equals(), comparing equals() is actually calling methods in Object to see if they are the same Object (i.e. comparing memory addresses).
- If you override only equals() but not hashCode (), the HashMap will be blocked for a different Key at a judgment time.
So to use an object as the key of a HashMap, you must override the object’s hashCode and equals methods. Make sure that hashCode is equal to equals is also true.
- The diagram is as follows:
This seems like a simple question, but many junior programmers can’t explain it either because they are not familiar with HashMap or because they don’t fully understand the meaning of the two methods.
To store custom objects in the “keys” section of the HashMap, be sure to override the equals and hashCode methods. Two more platitudes!
- If two objects == are equal, their HashCode must be equal, and vice versa.
- If two equals objects are equal, their HashCode must be equal, and vice versa.
Try it by yourself