I. Introduction to the Hashcode () method and the Equals () method
The Java base class object provides methods in which the Equals () method is used to determine whether two objects are equal, and the Hashcode () method is used to calculate the hash code of the object. Both Equals () and hashcode () are not final methods and can be overridden (overwrite).
1. Equal () method
The Equals () method in the object class is implemented as follows:
public boolean equals (Object obj) {
return (this = = obj);
}
Through this implementation, it can be seen that the implementation of the object class uses the most differentiated algorithm, that is, as long as two objects are not the same object, then equals () must return FALSE.
Although we can override the Equals () method when defining a class, there are some caveats, and the JDK describes the conventions that implement the Equals () method:
(1) Reflexivity: x.equals (x) must return True.
(2) Symmetry: The return value of X.equals (y) and y.equals (x) must be equal.
(3) transitivity: X.equals (y) is true,y.equals (z) and True, then X.equals (z) must be true.
(4) Consistency: If the information used by object X and Y in equals () does not change, then the X.equals (Y) value is always the same.
(5) Non-null:x is not null,y is null, then X.equals (y) must be false.
2.hashCode () method
(i) the hashcode () of object:
The declaration of the Hashcode () method in the object class is as follows:
public
native
int
hashCode();
As you can see, hashcode () is a native method, and the return value type is shaping; in fact, the native method returns the address of the object in memory as a hash code, which guarantees that the return value of the different objects is different.
Similar to the Equals () method, the Hashcode () method can be overridden. The role of the Hashcode () method in the JDK, as well as considerations for implementation, are explained:
(1) hashcode () works in a hash table, such as Java.util.HashMap.
(2) If the information used by the object in Equals () has not changed, then the Hashcode () value is always the same.
(3) If two objects are judged equal using the Equals () method, the Hashcode () method should also be equal.
(4) If two objects are judged to be unequal using the Equals () method, Hashcode () is not required and must not be equal, but developers should realize that unequal objects produce different hashcode to improve the performance of the hash table.
Role of 3.hashCode ()
In general, Hashcode () works in a hash table, such as HashSet, HashMap, and so on.
When we add object objects to a hash table (such as HashSet, HashMap, and so on), we first call the Hashcode () method to calculate the hash code of object, and the hash code allows you to directly position the location of object in the hash table (typically hash code is redundant to the Hashtable size). If there are no objects at that location, you can insert the object directly into that position, and if there are objects (possibly multiple, through the linked list), the Equals () method is called to compare the objects to object equality, and if they are equal, no object is required; The object is added to the linked list.
This also explains why Equals () is equal, and hashcode () must be equal. If two objects equals () are equal, they should only occur once in a hash table (such as HashSet, HashMap, and so on), and if hashcode () are unequal, they will be hashed to different locations in the hash table, more than once.
In fact, in the JVM, the loaded object consists of three parts in memory: The object header, the instance data, and the padding. The object header includes a pointer to the type of the object and Markword, while the Markword contains the object's GC generational age information, the lock state information, but also includes the object's Hashcode; object instance data is a valid information that the object is actually stored The fill part only acts as a placeholder because the hotspot requires that the object start address must be an integer multiple of 8 bytes.
Implementation of Equals () and Hashcode () in 4.String
The relevant implementation code in the string class is as follows:
1234567891011121314151617181920212223242526272829303132333435 |
private final char value[];
private int hash;
// Default to 0
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
;
}
public int hashCode() {
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;
}
|
The following points can be seen through the code:
The data of a, string is final, that is, once a string object is created, it cannot be modified; the shape is like string s = "Hello"; s = "World"; when s = "world" is executed, not the value of the string object becomes "world", but a new string object is created, and the S reference points to the new object.
b, the string class caches the result of hashcode () as a hash value, improving performance.
C, the String Object Equals () is equal to the same string object, the same length, and the string value is exactly the same, and the two are not required to be the same object.
D, string hashcode () Calculation formula is: s[0]*31^ (n-1) + s[1]*31^ (n-2) + ... + s[n-1]
In the hashcode () calculation process, why the number 31 is used, mainly for the following reasons:
A, the use of prime numbers to calculate the hash code, because of the characteristics of prime numbers, it is multiplied with other numbers, the results are only more likely to calculate the probability of a hash collision less.
b, the larger the number of prime numbers used, the smaller the probability of a hash collision, but the slower the computation is, and 31 is the tradeoff between hash collisions and performance, which is actually the result of experimental observations.
C, the JVM will automatically optimize for 31: * i = = (i << 5) –i
5. How to rewrite Hashcode ()
This section first describes the principles that the overriding hashcode () method should follow, and then describes the common hashcode () override method.
(i) The principle of rewriting the hashcode ()
We know from the previous description that rewriting hashcode requires adherence to the following principles:
(1) if the Equals () method is overridden and the check condition "two objects are judged equal using the Equals () method, then the Hashcode () method should also be equal" whether it is true, or if not, the Hashcode () method is overridden.
(2) The Hashcode () method cannot be too simple, otherwise there is too much hash conflict.
(3) The Hashcode () method can not be too complex, otherwise the computational complexity is too high, affecting the performance.
(ii) Hashcode () rewrite method
A, initialize an shaping variable, assigning a nonzero constant value to the variable, such as int result = 17;
B, select all the fields used in the Equals method for comparison (only the domain used in equals () is selected to guarantee the 1th of the above principles), and then the properties for each domain are evaluated:
(1) If it is a Boolean value, the F is calculated. 1:0
(2) If byte\char\short\int, calculate (int) F
(3) If it is a long value, the calculation (int) (f ^ (f >>> 32))
(4) If it is a float value, calculate float.floattointbits (f)
(5) If it is a double value, calculate Double.doubletolongbits (f), then return a long, then use the rule (3) to handle long, get int
(6) If the object is applied, if a recursive invocation is used in the Equals method, then the hashcode also takes a recursive call to hashcode in the same way. Otherwise, you need to calculate a paradigm for this field, such as when the value of this field is null, then the hashcode value is 0.
(7) In the case of arrays, each element needs to be treated as a separate domain. The Java.util.Arrays.hashCode method contains 8 basic types of arrays and hashcode computations of reference arrays, as in the previous algorithm.
C, finally, the hash code of each domain is merged into the object's hashing code.
This is illustrated by an example below. In this example, the person class overrides the Equals () method and the Hashcode () method. Because only the name domain and the age domain are used in the Equals () method, only the name and age fields are computed in the Hashcode () method.
For string type name fields, the Hashcode () method of string is used directly, and for an age domain of type int, its value is used as the hash of the field.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152 |
public class Person {
private String name;
private int age;
private boolean gender;
public Person() {
super
();
}
public String getName() {
return name;
}
public void setName(String name) {
this
.name = name;
}
public int getAge() {
return age;
}
public void setAge(
int age) {
this
.age = age;
}
public boolean isGender() {
return gender;
}
public void setGender(
boolean gender) {
this
.gender = gender;
}
@Override
public boolean equals(Object another) {
if (
this == another) {
return true
;
}
if (another
instanceof Person) {
Person anotherPerson = (Person) another;
if (
this
.getName().equals(anotherPerson.getName()) &&
this
.getAge() == anotherPerson.getAge()) {
return true
;
}
else {
return false
;
}
}
return false
;
}
@Override
public int hashCode() {
int hash =
17
;
hash = hash *
31 + getName().hashCode();
hash = hash *
31 + getAge();
return hash;
}
}
|
Eighth Week Java EE jobs