Java-equals () and hashCode () Methods
The java. lang. Object Class has two very important methods:
12 |
public boolean equals(Object obj) public int hashCode() |
Object
Class is the basis of the class inheritance structure, so it is the parent class of each class. All objects, including arrays, are implemented inObject
Class.
Equals ()Detailed description
equals()
The method is used to determine whether other objects are equal to the object.
The equals () method is defined in the object class as follows:
public boolean equals(Object obj) { return (this == obj); }
It is obvious that the address values of the two objects are compared (that is, whether the reference is the same ). However, we know that when using the equals () method, such encapsulation classes as String, Math, Integer, and Double, the equals () method of the object class has been overwritten.
For example, in the String class:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n– != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
Obviously, this is the content comparison, but it is no longer the address comparison. Similarly, Math, Integer, and Double classes all overwrite the equals () method to compare the content. Of course, the basic type is to compare values.
It has the following features:
Self-defense(Reflexive ). For anynull
X,x.equals(x)
Yestrue
.
Symmetry(Distributed RIC ). For anynull
Reference Valuex
Andy
, When and only whenx.equals(y)
Yestrue
,y.equals(x)
Yestrue
.
Transmission(Transitive ). For anynull
Reference Valuex
,y
Andz
, Ifx.equals(y)
Yestrue
, At the same timey.equals(z)
Yestrue
, Thenx.equals(z)
Yestrue
.
Consistency(Consistent ). For anynull
Reference Valuex
Andy
If the object information used for equals comparison is not modifiedx.equals(y)
Either return consistentlytrue
Either return consistentlyfalse
.
For anynull
Reference Valuex
,x.equals(null)
Returnfalse
.
ForObject
Class,equals()
Methods implement the equivalence relationship with the largest possibility of difference on objects, that is, for any non-null
Reference Valuex
Andy
, When and only whenx
Andy
If the same object is referenced, this method returnstrue
.
Note that whenequals()
When the method is override,hashCode()
Override. GenerallyhashCode()
For the implementation of the method, the hash code of the same objects must be equal.
Detailed description of hashcode () method
hashCode()
Method returns a hash code value to the object. This method is used for hash tables, such as HashMap.
Its nature is:
During the execution of a Java application, if the information provided by an object to equals for comparison is not modified, the object is called multiple times.hashCode()
Method, which must always return the same integer.
If the two objectsequals(Object)
The methods are equal.hashCode()
The method must generate the same integer result.
Not required accordingequals(java.lang.Object)
Two objects with different methods are called.hashCode()
The method must generate different integer results. However, programmers should realize that generating different integer results for different objects may improve the performance of hash tables.
A large number of practices show thatObject
Class definedhashCode()
Method returns different integers for different objects.
In the object class, hashCode is defined as follows:
public native int hashCode();
The description is a local method, which is implemented based on local machines. Of course, we can overwrite the hashcode () method in the class we write, such as String, Integer, Double, and so on. These classes all overwrite the hashcode () method. For example, the hashcode () method defined in the String class is as follows:
public int hashCode() { int h = hash; if (h == 0) { int off = offset; char val[] = value; int len = count; for (int i = 0; i < len; i++) { h = 31 * h + val[off++]; } hash = h; } return h; }
Explain this program (written in the String API): s [0] * 31 ^ (n-1) + s [1] * 31 ^ (n-2) +... + S [n-1]
Using the int algorithm, Here s [I] is the string's I character, n is the length of the string, ^ represents the power (the hash code of the Null String is 0 ).
To understand the role of hashCode, you must first know the set in Java.
In general, collections in Java have two types: List and Set. The elements in the former set are ordered, and the elements can be repeated. The latter elements are unordered, but the elements cannot be repeated. The following question is raised: to ensure that the elements are not repeated, what is the basis for determining whether the two elements are repeated?
This is the Object. equals method. However, if each added element is checked once, when there are many elements, the number of times that the elements added to the set are compared is very large. That is to say, if there are already 1000 elements in the Set, it will call the 1,001st equals method when 1000 elements are added to the set. This will obviously greatly reduce the efficiency.
Therefore, Java uses the principle of hash tables. Hash is actually a personal name. As he proposed a Hash algorithm, he named it. Hash algorithms, also known as hash algorithms, are used to directly specify an address based on a specific data algorithm, which can be easily understood by beginners, the hashCode method actually returns the physical address of the Object Storage Service (which may not actually be ).
In this way, when a set needs to add a new element, the hashCode method of this element is called first, and the physical location where it should be placed can be located at once. If there are no elements in this position, it can be directly stored in this position without any comparison. If there are already elements in this position, you can call its equals method to compare it with the new element. If it is the same, it will not be saved. If it is different, other addresses will be hashed. Therefore, there is a conflict resolution problem. In this way, the number of actually called equals methods is greatly reduced, and it takes almost one or two times.
In short, hashcode can greatly reduce the number of object comparisons and improve the search efficiency in Collection Search!
The eqauls and hashCode methods of Java objects are defined as follows:
1. Equal(Same)The object must have an equal hash code (or hash code ).
2. If two objects have the same hashCode, they are not necessarily the same.
The following describes the equal method and hashCode method of the Object API:
- If two objects are equal according to
equals(Object)
Method, then callinghashCode
Method on each of the two objects must produce the same integer result.
- It isNotRequired that if two objects are unequal according to
equals(java.lang.Object)
Method, then callinghashCode
Method on each of the two objects must produce distinct integer results. However, the programmer shocould be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
- The above API description is an official description of the previous two points
For the first point, an equal (identical) object must have an equal hash code (or hash code). Why?
Imagine if two Java objects A and B, A and B are equal (eqauls returns true), but the hash codes of A and B are different, then, the index of the array location inside the HashMap calculated by the hash code when A and B are stored in the HashMap may be different. Therefore, A and B are likely to be stored in the HashMap at the same time, obviously, equal/identical elements are not allowed to be stored in HashMap at the same time, and HashMap is not allowed to store duplicate elements.
For the second point, the two objects have the same hashCode, but they are not necessarily the same.
That is to say, the hashCode of different objects may be the same. If two Java objects A and B, A and B are not equal (eqauls returns false), but the hash codes of A and B are equal, when both A and B are stored in HashMap, A hash conflict occurs, that is, A and B are stored in the same location index of the HashMap internal array. Then, HashMap creates A chain table at this location, put A and B together in this position. Obviously, this situation does not violate the HashMap usage principle and is allowed. Of course, the fewer hash conflicts, the better. Try to use a good hash algorithm to avoid hash conflicts.
Therefore, Java specifies the eqauls method and hashCode method as follows:
1. If the two objects are the same, their hashCode values must be the same;
2. If the hashCode of the two objects is the same, they are not necessarily the same (the same object here refers to comparison using the eqauls method ).
If you do not do this as required, you will find that the same object can appear in the Set, and the efficiency of adding new elements will be greatly reduced.
3. If equals () is equal, hashcode () must be equal. If equals () is not equal, their hashcode () is not equal.
In other words, hashcode () may be equivalent to two objects whose equals () methods are not equal (in my understanding, the hash code is generated due to a conflict ). In turn, hashcode () is not equal, and equals () is certainly available. hashcode () is equal, and equals () may be equal or not.
In the object class, the hashcode () method is a local method and returns the address value of the object. The equals () method in the object class compares the address values of the two objects, if equals () is equal, the address values of the two objects are equal, and hashcode () is equal;In the String class, equals () returns a comparison of the content of two objects.When the content of the two objects is equal, the Hashcode () method analyzes the rewrite code of the String class. You can also know that the returned result of hashcode () is equal. Similarly, we can know that the overwritten equals () and hashcode () methods in Integer and Double encapsulation classes are also suitable for this principle. Of course, the class that has not been overwritten will also follow this principle after it inherits the equals () and hashcode () Methods of the object class.
The close relationship between Hashset, Hashmap, and Hashtable and hashcode () and equals ()
Hashset inherits the Set interface and implements the Collection interface. This is a hierarchical relationship. So what principle does the storage operations in Hashset, Hashmap, and Hashtable access objects?
The following example uses HashSet for analysis. We all know that repeated objects are not allowed in hashset, And the element location is also unknown. In hashset, how does one determine whether the elements are repeated? In a java set, the rule for determining whether two objects are equal is:
1. Determine whether the hashCode of the two objects is equal
If they are not equal, the two objects are considered not equal.
If equal, transfer to 2
(This is only required to improve storage efficiency. In theory, it is not acceptable. However, if it is not, the actual usage of the aging rate will be greatly reduced, so we need it here .)
2. Determine whether two objects are equal using the equals operation
If they are not equal, the two objects are considered not equal.
If the two objects are equal, equals () is the key to determining whether the two objects are equal)
Why are there two principles? Can't I use the first one? No, because as mentioned earlier, the equals () method may not be equal when hashcode () is equal. Therefore, you must use the 2nd rules to ensure that non-repeating elements are added.
Example 1:
1 package com.bijian.study; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 import java.util.Set; 6 7 public class HashSetTest { 8 9 public static void main(String args[]) {10 String s1 = new String("aaa");11 String s2 = new String("aaa");12 System.out.println(s1 == s2);13 System.out.println(s1.equals(s2));14 System.out.println(s1.hashCode());15 System.out.println(s2.hashCode());16 Set hashset = new HashSet();17 hashset.add(s1);18 hashset.add(s2);19 Iterator it = hashset.iterator();20 while (it.hasNext()) {21 System.out.println(it.next());22 }23 }24 }
Running result:
falsetrue9632196321aaa
This is because the String class has overwritten the equals () and hashcode () methods, so hashset considers them to be equal objects and adds them again.
Example 2:
1 package com.bijian.study; 2 3 import java.util.HashSet; 4 import java.util.Iterator; 5 6 public class HashSetTest { 7 8 public static void main(String[] args) { 9 HashSet hs = new HashSet();10 hs.add(new Student(1, "zhangsan"));11 hs.add(new Student(2, "lisi"));12 hs.add(new Student(3, "wangwu"));13 hs.add(new Student(1, "zhangsan"));14 15 Iterator it = hs.iterator();16 while (it.hasNext()) {17 System.out.println(it.next());18 }19 }20 }21 22 class Student {23 int num;24 String name;25 26 Student(int num, String name) {27 this.num = num;28 this.name = name;29 }30 31 public String toString() {32 return num + ":" + name;33 }34 }
Running result:
1:zhangsan 3:wangwu 2:lisi 1:zhangsan
Why does hashset add equal elements? Is it against the hashset principle? The answer is: no. Because different hash code values are generated when two new Student (1, "zhangsan") objects are compared based on hashcode, so hashset treats it as a different object. Of course, the values returned by the equals () method also vary.
Why does it generate different hash code values? Didn't we generate the same hash code when comparing s1 and s2? The reason is that the Student class we write does not repeat the hashcode () and equals () methods. Therefore, during comparison, it is the hashcode () method in the inherited object class, the hashcode () method in the object class is a local method, which compares the object address (reference address) and creates an object using the new method, the two generated objects are of course different. The result is that the values returned by the hashcode () of the two objects are different. Therefore, Hashset treats them as different objects.
How can this problem be solved? The answer is: Re-hashcode () and equals () methods in the Student class.
class Student { int num; String name; Student(int num, String name) { this.num = num; this.name = name; } public int hashCode() { return num * name.hashCode(); } public boolean equals(Object o) { Student s = (Student) o; return num == s.num && name.equals(s.name); } public String toString() { return num + ":" + name; }}
Running result:
1:zhangsan 3:wangwu 2:lisi
We can see that the duplicate element problem has been eliminated. According to the rewrite method, even if we call new Student (1, "zhangsan") twice, when we get the object's hash code, according to the hashcode () method of rewriting, the obtained hash code must be the same. Of course, based on the equals () method, we can also judge that it is the same, so they are treated as repeated elements when added to the hashset set.
Rewrite equals () and hashcode () summary:
1. The focus is on equals. Rewriting hashCode is only a technical requirement (to improve efficiency)
2. Why rewrite equals? In java's collection framework, equals is used to determine whether two objects are equal.
3. In hibernate, the set is often used to save related objects, and the set cannot be repeated. When adding an element to a HashSet set, you only need to override equals. However, when there are many elements in a hashset, or the rewritten equals () method is complicated, we only use the equals () method for comparison and judgment, and the efficiency will be very low, therefore, hashCode () is introduced to improve efficiency and this is necessary. For example, you can write as follows:
Public int hashCode () {return 1; // equivalent to invalid hashcode}
The result of this operation is that it cannot be judged when comparing hash codes, because each object returns a hash code of 1 and each time it must be compared to equals () the method can be used to determine whether it is repeated, which will greatly reduce the efficiency.
Reference:
Correctly Use The equals () and hashCode () methods in Java
Detailed explanation of equals () and hashCode () methods in Java in-depth analysis of the application of hashCode and hashCode of Java objects in the underlying data structure of HashMap
Answers to several questions about Java hashCode () and equals ()