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 > 0) {
char val[] = value;
for (int i = 0; i < 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