About hashCode and equals methods in Java

Go directly to the source code!

public native int hashCode();
/**
* Returns a hash code value for the object. This method is
* supported for the benefit of hash tables such as those provided by
* {@link java.util.HashMap}.
* <p>
* The general contract of {@code hashCode} is:
* <ul>
* <li>Whenever it is invoked on the same object more than once during
* an execution of a Java application, the {@code hashCode} method
* must consistently return the same integer, provided no information
* used in {@code equals} comparisons on the object is modified.
* This integer need not remain consistent from one execution of an
* application to another execution of the same application.
* <li>If two objects are equal according to the {@code equals(Object)}
* method, then calling the {@code hashCode} method on each of
* the two objects must produce the same integer result.
* <li>It is <em>not</em> required that if two objects are unequal
* according to the {@link java.lang.Object#equals(java.lang.Object)}
* method, then calling the {@code hashCode} method on each of the
* two objects must produce distinct integer results. However, the
* programmer should be aware that producing distinct integer results
* for unequal objects may improve the performance of hash tables.
* </ul>
* <p>
* As much as is reasonably practical,the hashCode method defined by
* class {@code Object} does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java™ programming language.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/

The first sentence of the official document said that this hashCode method exists mainly for hash tables, such as HashSet, HashTable and HashMap all use hash tables to store data (Key Value), and the hash calculated by hashCode The value can uniquely determine an element. With the hash value, the element can be quickly located and the performance of the hash table can be improved. The following are the points specified by hashCode:

  • In the same Java application, as long as it is the same object, no matter how many times you call the hashCode method, its return value should be the same. In different java applications, this return value can be different.
  • If two objects are judged to be the same by the equals method, then the return values ​​of the two objects calling the hashCode method must also be the same.
  • If the two objects are judged to be unequal by calling the equals method of the top-level parent class (Object), then the return values ​​of the two objects calling the hashCode method must also be different.
  • However, as programmers, we can override this method in subclasses, so that as long as the values ​​in the objects are equal, then the two objects are equal, but this may reduce the performance of the hash table. (According to the actual needs to judge whether to rewrite it)

For these reasons, the hashCode method in the object class must return different values ​​for different objects (this is determined by the internal conversion method, usually this value is the actual address of the object in the JVM)

Then the value of this value is definitely not the address where the object is actually located! For example: hashCode of 8 wrapper classes

  Wrapper class : Boolean Byte Short Integer Long Character Float Doubles

Let's see how they override the parent class's method

  Boolean@Override

public int hashCode() { 
return Boolean.hashCode(value);
}

/**
* Returns a hash code for a {@code boolean} value; compatible with
* {@code Boolean.hashCode()}.
*
* @param value the value to hash
* @return a hash code value for a {@code boolean} value.
* @since 1.8
*/
public static int hashCode(boolean value) {
return value ? 1231 : 1237;
}
It can be seen that the Boolean type Variables are compared to Boolean values. If both are true, then return 1231. If false, then return 1237. It can be said that as long as it
is an object of type Boolean, as long as the value is the same, then they are the same.

  Byte

@Override 
public int hashCode() {
return Byte.hashCode(value);
}

/**
* Returns a hash code for a {@code byte} value; compatible with
* {@code Byte.hashCode()}.
*
* @ param value the value to hash
* @return a hash code value for a {@code byte} value.
* @since 1.8
*/
public static int hashCode(byte value) {
return (int)value;
}
For objects of type Byte, The value of hashCode is the value of

Integer after he is cast to int type , and Short is the value of

  Long after being converted to int type.
@Override
public int hashCode() {
return Long.hashCode(value);
}

/**
* Returns a hash code for a {@code long} value; compatible with
* {@code Long.hashCode()}.
*
* @param value the value to hash
* @return a hash code value for a {@code long} value.
* @since 1.8
*/
public static int hashCode(long value) {
return (int)(value ^ (value >>> 32));
}
The return value is the difference between itself and its signed right-shifted value or the obtained value and then cast to int type. 

  Character directly calls the hashCode method Float
of the Object class
  
public static int hashCode(float value) {
return floatToIntBits(value);
}
public static int floatToIntBits(float value) {
int result = floatToRawIntBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & FloatConsts.EXP_BIT_MASK) ==
FloatConsts.EXP_BIT_MASK) &&
(result & FloatConsts.SIGNIF_BIT_MASK) != 0)
result = 0x7fc00000;
return result;
}public static native int floatToRawIntBits(float value);
The API says this: Returns the hash code of this float object. The result is the integer bit representation, as produced by the method floatToIntBits(float) , which is the double
value of the original floating point represented by this floating point object

  
Similar to the Floate type, the 
API says this: Returns the hash code of this Double object. The result is a unique or two half-integer bit representation of two parts, produced entirely by the method
doubleToLongBits(double)

Through the above words, it is clear that this method must be inseparable from the equals method . No, the source code is followed by the equals method

public boolean equals(Object obj) {
return (this == obj);
}
/**
* Indicates whether some other object is "equal to" this one.
* <p>
* The {@code equals} method implements an equivalence relation
* on non-null object references:
* <ul>
* <li>It is <i>reflexive</i>: for any non-null reference value
* {@code x}, {@code x.equals(x)} should return
* {@code true}.
* <li>It is <i>symmetric</i>: for any non-null reference values
* {@code x} and {@code y}, {@code x.equals(y)}
* should return {@code true} if and only if
* {@code y.equals(x)} returns {@code true}.
* <li>It is <i>transitive</i>: for any non-null reference values
* {@code x}, {@code y},and {@code z}, if
* {@code x.equals(y)} returns {@code true} and
* {@code y.equals(z)} returns {@code true}, then
* {@code x.equals(z)} should return {@code true}.
* <li>It is <i>consistent</i>: for any non-null reference values
* {@code x} and {@code y}, multiple invocations of
* {@code x.equals(y)} consistently return {@code true}
* or consistently return {@code false}, provided no
* information used in {@code equals} comparisons on the
* objects is modified.
* <li>For any non-null reference value {@code x},
* {@code x.equals(null)} should return {@code false}.
* </ul>
* <p>
* The {@code equals} method for class {@code Object} implements
* the most discriminating possible equivalence relation on objects;
* that is, for any non-null reference values {@code x} and
* {@code y}, this method returns {@code true} if and only
* if {@code x} and {@code y} refer to the same object
* ({@code x == y} has the value {@code true}).
* <p>
* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
*
* @param obj the reference object with which to compare.
* @return {@code true} if this object is the same as the obj
* argument; {@code false} otherwise.
* @see #hashCode()
* @see java.util.HashMap
*/

Directly compare whether two objects are the same object

The following are the rules that need to be met to override the equals method

  Reflexive : for any non-null reference x, x.equals(x) should return true

  Symmetry : For any reference x and y, if and only if it  y.equals(x) returns  true, x.equals(y) it should also return true

  Transitive : For any reference x, y and z, if  x.equals(y)returned  true, y.equals(z) it should return the same result

  Consistencyx.equals(y) : Repeated calls  should return the same result if the objects referenced by x and y have not changed 

  For any non-null reference x, x.equals(null) should return false

For variables of non-null reference types, (without overriding equals and hashCode), they are equal if they point to the same address in the memory space. It is better to override the equals method as well. The main purpose is to maintain the relationship with the hashcode (the same object must have the same hash value).

Several wrapper classes that rewrite the equals method: File String Date 8 wrapper classes, they all compare the type and content regardless of whether the reference is the same object,

Such as:

  String 's equals method

public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
First compare whether it is the same object, then compare the length, and finally compare the values. If they are all equal, then they are equal.

Example :

public static void main(String[] args) {
String str1 = "BB";
String str2 = str1;
String str3 = new String("BB");
String str4 = new String("BB");

System.out.println(str1==str2);
System.out.println(str2==str3);
System.out.println(str3==str4);

System.out.println(str1.equals(str3));
System.out.println(str3.equals(str4));
}
Result: 
  true
  false
  false
  true
  true
Now try the custom class
  
public class Person { 
Integer id;
String name;
}
At this time I did not override the equals method
public static void main(String[] args) { 
Person person1 = new Person(1, "Xiao Ming");
Person person2 = new Person(1, "Xiao Ming");

System.out.println(person1 == person2);
System .out.println(person1.equals(person2));
}
Result:
  false
  false
When I rewrite the equals method of the parent class
and then print it again
  false
  true
How to rewrite equals and hashCode ?

  Most of the popular IDEs have this function, of course, you can also write your own, but I was lazy and generated it directly

@Override 
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}

Person person = ( Person) o;

if (id != null ? !id.equals(person.id) : person.id != null) {
return false;
}
return name != null ? name.equals(person.name) : person. name == null;
}

@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (name != null ? name.hashCode() : 0) ;
return result;
}

The return value of hashCode is customized, for example, you can change 31 to 32

Tips: After understanding the JVM, the understanding of these two methods will be more thorough, combined with the source code to eat

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325377179&siteId=291194637