Details on rewriting hashcode () and equals () methods

Hashcode () and equals () methods can be said to be a major feature of Java's completely object-oriented. They not only facilitate our programming, but also bring many dangers. In this article, we will discuss how to correctly understand and use these two methods

How to override the equals () method

If you decide to rewrite the equals () method, you must be clear about the risks and make sure you can write a robust equals () method. It must be noted that after rewriting equals (), you must rewrite the hashcode () method. The specific reasons will be explained later

Let's take a look at the description of the equals () method in the javase 7 specification:

・It is reflexive: for any non-null reference value x,x.equals(x) should return true. ・It is symmetric: for any non-null reference values x and y,x.equals(y) should return true if and only if y.equals(x) returns true. ・It is transitive: for any non-null reference values x,y, and z,if x.equals(y) returns true and y.equals(z) returns true,then x.equals(z) should return true. ・It is consistent: for any non-null reference values x and y,multiple invocations of x.equals(y) consistently return true or consistently return false,provided no information used in equals comparisons on the objects is modified. ・For any non-null reference value x,x.equals(null) should return false.

This passage uses a lot of arithmetic numbers in discrete mathematics. Briefly explain:

1. Reflexivity: A. equals (a) returns true 2. Symmetry: if A. equals (b) returns true, B. equals (a) also returns true 3. Transitivity: if a.equals (b) is true and b.equals (c) is true, a.equals (c) must also be true To put it bluntly, a = B, B = C, then a = C. 4 Consistency: A. equals (b) must always return true as long as the state of a and B objects does not change 5. A. equals (null) returns false

I believe that as long as people who are not majoring in mathematics do not call on the above things. In practical application, we only need to rewrite the equals () method according to certain steps. For convenience of explanation, we first define a programmer class (coder):

What we want is that if the name and age of two programmer objects are the same, we will think that the two programmers are the same person. At this time, we need to rewrite their equals () method. Because the default equals () actually determines whether two references point to the same object in the internal, which is equivalent to = =. The following three steps should be followed when Rewriting:

1. Judge whether it is equal to itself

2. Use instanceof operator to judge whether other is an object of coder type

3. Compare the data fields you defined in the coder class, name and age. There should be no less

Seeing this, some people may ask that there is a cast in step 3. If someone passes an integer class object to this equals, will ClassCastException be thrown? In fact, this worry is superfluous. Because we have judged instanceof in the second step. If other is a non coder object or even other is null, false will be returned directly in this step, so that the subsequent code will not be executed

The above three steps are also recommended in effective Java, which can basically ensure that there is no mistake

How to override the hashcode () method

In the javase 7 specification,

"Note that it is generally necessary to override the hashCode method whenever this method(equals) is overridden,so as to maintain the general contract for the hashCode method,which states that equal objects must have equal hash codes."

If you rewrite the equals () method, you must remember to rewrite the hashcode () method. We have all learned the hash table in the college computer data structure course, and the hashcode () method serves the hash table

When we use collection classes such as HashMap and HashSet that start with hash, hashcode () will be implicitly called to create hash mapping relationship. We will explain this later. Here, we will focus on the writing of hashcode () method

Effective Java provides a way to avoid hash conflicts to the greatest extent, but I personally don't think it's necessary to make it so troublesome for general applications. If you need to store tens of thousands or millions of objects in your HashSet, you should strictly follow the method given in the book. If you write a small and medium-sized application, Then the following principles are sufficient:

Ensure that all members in the coder object can be reflected in hashcode

For this example, we can write:

Where int result = 17, you can also change it to 20, 50, etc. I'm suddenly curious to see how the hashcode () method in the string class is implemented. Check the document:

"Returns a hash code for this string. The hash code for a String object is computed as

using int arithmetic,where s[i] is the ith character of the string,n is the length of the string,and ^ indicates exponentiation. (The hash value of the empty string is zero.) "

Calculate the N - 1 power of the ASCII code of each character, and then add it. It can be seen that sun's implementation of hashcode is very rigorous This can avoid the same hashcode for two different strings to the greatest extent

The risk of overriding equals() without overriding hashcode()

The concept of bucket is referenced in Oracle's hash table implementation, as shown in the following figure:

As can be seen from the above figure, the hash table with bucket is roughly equivalent to the combination of hash table and linked list. That is, a linked list will be hung on each bucket, and each node of the linked list is used to store objects. Java uses the hashcode () method to determine which bucket an object should be located in, and then looks it up in the corresponding linked list. Ideally, If your hashcode () method is robust enough, there will be only one node in each bucket, which realizes the constant time complexity of the search operation. That is, no matter what memory your object is placed in, I can immediately locate the area through hashcode () without traversing the search from beginning to end. This is also the main application of hash tables

For example:

When we call the put (object o) method of HashSet, we will first locate the corresponding bucket according to the return value of o.hashcode(). If there is no node in the bucket, put o here. If there is already a node, hang o to the end of the linked list. Similarly, when we call contains (object o), Java will locate the corresponding bucket through the return value of hashcode(), Then call the equals () method in turn at the nodes in the corresponding linked list to determine whether the objects in the nodes are the objects you want

Let's experience this process through an example:

Let's first create two new coder objects:

Suppose we have overridden the equals () method of coder instead of the hashcode () method:

Then we construct a HashSet and put the C1 object into the set:

Re execution:

We expect the contains (C2) method to return true, but it actually returns false

The name and age of C1 and C2 are the same. Why do I call contains (C2) after putting C1 in the HashSet and return false? This is what hashcode () is doing. Because you didn't rewrite the hashcode () method, HashSet will look in different buckets when looking for C2. For example, C1 is placed in bucket 05, but it is found in bucket 06 when looking for C2. Of course, we can't find it. Therefore, the purpose of rewriting hashcode () is that when A. equals (b) returns true, a, The hashcode () of B should return the same value

Should I have hashcode () return a fixed number every time

Someone might rewrite it like this:

If so, HashMap, HashSet and other collection classes will lose their "hash meaning". In < effective Java >, the hash table degenerates into a linked list. If hashcode() returns the same number every time, all objects will be placed in the same bucket, and the linked list will be traversed every time the lookup operation is performed, So we'd better provide a robust hashcode ()

summary

The above is all the details about rewriting hashcode () and equals () methods in this article. I hope it will be helpful to you. Interested friends can continue to refer to other related topics on this site. If there are deficiencies, please leave a message to point out. Thank you for your support!

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>