Introduction to the hashcode method in Java

Source: Internet
Author: User

Introduction to the hashcode method in Java

The hash table data structure is certainly not unfamiliar to most people, and hash tables are used in many places to improve the search efficiency. There is a method in the Object class of Java:

public native int hashCode();

According to the declaration of this method, this method returns an int type value and is a local method. Therefore, no specific implementation is provided in the Object class.

Why does the Object class need such a method? What does it do? Today, we will discuss the hashCode method in detail.

I. Role of the hashCode Method

For programming languages that contain the container type, hashCode is basically involved. In Java, the hashCode method works properly with hash-based sets. Such hash sets include HashSet, HashMap, and HashTable.

Why? When inserting an object into a collection, how does one determine whether the object already exists in the collection? (Note: duplicate elements are not allowed in the set)

Most people may think of calling the equals method to compare one by one. This method is indeed feasible. However, if there are already 10 thousand or more data entries in the collection, the efficiency will inevitably be a problem if the equals method is used to compare them one by one. At this time, the role of the hashCode method is reflected. When a set needs to add a new object, the hashCode method of this object is called first to obtain the corresponding hashcode value, in fact, in the specific implementation of HashMap, a table is used to save the hashcode value of the object that has already been stored. If the hashcode value is not in the table, it can be saved directly, no comparison is required. If the hashcode value exists, the equals method of the hashcode is called to compare it with the new element. If the hashcode value is the same, the other addresses are hashed, therefore, there is a conflict resolution problem, which greatly reduces the number of calls to the equals method: in Java, the hashCode method maps information related to objects (such as Object Storage addresses and object fields) into a value based on certain rules. This value is called as a hash value. The following code is the specific implementation of the put Method in java. util. HashMap:

public V put(K key, V value) {        if (key == null)            return putForNullKey(value);        int hash = hash(key.hashCode());        int i = indexFor(hash, table.length);        for (Entry<K,V> e = table[i]; e != null; e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {                V oldValue = e.value;                e.value = value;                e.recordAccess(this);                return oldValue;            }        }        modCount++;        addEntry(hash, key, value, i);        return null;    }

The put method is used to add new elements to the HashMap. According to the specific implementation of the put method, the hashCode method is called to obtain the hashCode value of the element, check whether the hashCode value exists in the table. If yes, call the equals method to re-determine whether the element exists. If yes, update the value, otherwise, add the new element to the HashMap. It can be seen from this that the hashCode method exists to reduce the number of calls to the equals method and thus improve program efficiency.

If you are not clear about the data structure of the hash table, refer to these blog posts;

Http://www.cnblogs.com/jiewei915/archive/2010/08/09/1796042.html

Http://www.cnblogs.com/dolphin0520/archive/2012/09/28/2700000.html

Http://www.java3z.com/cwbwebhome/article/article8/83560.html? Id = 4649

By default, the hashCode method in the Object class maps the storage address of the Object into an integer value (some friends mistakenly think that the returned hashCode is the storage address of the Object, it can only be said that the value returned by the hashCode method is related to the object's storage address, not its storage address ).

Therefore, some people may say that they can judge whether two objects are equal based on the hashcode value directly? Certainly not, because different objects may generate the same hashcode value. Although it is not possible to judge whether two objects are equal based on the hashcode value, two objects can be determined based on the hashcode value. If the hashcode values of two objects are different, they must be two different objects. To determine whether two objects are truly equal, you must use the equals method.

That is to say, for two objects, if the result obtained by calling the equals method is true, the hashcode values of the two objects must be equal;

If the equals method returns false, the hashcode values of the two objects are not necessarily different;

If the hashcode values of the two objects are not the same, the result obtained by the equals method must be false;

If the hashcode values of the two objects are equal, the results obtained by the equals method are unknown.

Ii. equals and hashCode Methods

In some cases, when designing a class, the programmer needs to override the equals method, such as the String class. However, you must note that the hashCode method must be rewritten while rewriting the equals method. Why?

The following is an example:

package com.cxh.test1;import java.util.HashMap;import java.util.HashSet;import java.util.Set;class People{private String name;private int age;public People(String name,int age) {this.name = name;this.age = age;}public void setAge(int age){this.age = age;}@Overridepublic boolean equals(Object obj) {// TODO Auto-generated method stubreturn this.name.equals(((People)obj).name) && this.age== ((People)obj).age;}}public class Main {public static void main(String[] args) {People p1 = new People("Jack", 12);System.out.println(p1.hashCode());HashMap<People, Integer> hashMap = new HashMap<People, Integer>();hashMap.put(p1, 1);System.out.println(hashMap.get(new People("Jack", 12)));}}

Here I only override the equals method, that is, if two People objects have the same name and age, they are considered to be the same person.

The original intention of this Code is to output the result of this Code as "1", but in fact it outputs "null ". Why? The reason is that while rewriting the equals method, I forgot to rewrite the hashCode method.

Although the equals method is rewritten to make the two objects of the same logical name and age be considered as equal objects (similar to the String class), you need to know that by default, the hashCode method maps the storage addresses of objects. It is not surprising that the output result of the above code is "null. The reason is very simple. p1 points to the object and

System. out. println (hashMap. get (new People ("Jack", 12); in this sentence, new People ("Jack", 12) generates two objects, and their storage addresses must be different. The specific implementation of the get method of HashMap is as follows:

public V get(Object key) {        if (key == null)            return getForNullKey();        int hash = hash(key.hashCode());        for (Entry<K,V> e = table[indexFor(hash, table.length)];             e != null;             e = e.next) {            Object k;            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))                return e.value;        }        return null;    }

So when hashmap performs get operations, the obtained hashcdoe values are different (note that the above Code may obtain the same hashcode value in some cases, but this probability is relatively small, because different storage addresses of the two objects may obtain the same hashcode value), The for loop will not be executed in the get method, and null is returned directly.

Therefore, if the output result of the above code is "1", it is very simple to rewrite the hashCode method so that the equals and hashCode methods are logically consistent.

package com.cxh.test1;import java.util.HashMap;import java.util.HashSet;import java.util.Set;class People{private String name;private int age;public People(String name,int age) {this.name = name;this.age = age;}public void setAge(int age){this.age = age;}@Overridepublic int hashCode() {// TODO Auto-generated method stubreturn name.hashCode()*37+age;}@Overridepublic boolean equals(Object obj) {// TODO Auto-generated method stubreturn this.name.equals(((People)obj).name) && this.age== ((People)obj).age;}}public class Main {public static void main(String[] args) {People p1 = new People("Jack", 12);System.out.println(p1.hashCode());HashMap<People, Integer> hashMap = new HashMap<People, Integer>();hashMap.put(p1, 1);System.out.println(hashMap.get(new People("Jack", 12)));}}

In this way, the output result is "1.

The following passage is taken from objective Java:

  • During program execution, as long as the information used for the comparison operation of the equals method is not modified, the hashCode method must always return the same integer for multiple calls to the same object.
  • If the two objects are equal according to the equals method, the hashCode method of the two objects must return the same integer result.
  • If the comparison between the two objects varies according to the equals method, the hashCode method may not necessarily return different integers.

The second and third articles are well understood, but the first one is often ignored. The P495 page in Java programming ideology also has the same article:

"The most important factor in designing hashCode () is that the same value should be generated whenever hashCode () is called for the same object. If a hashCdoe value is generated when an object is added to HashMap with put (), but another hashCode value is generated when get () is used, the object cannot be obtained. So if your hashCode method depends on variable data in the object, you should be careful, because when the data changes, hashCode () method will generate a different hash code ".

The following is an example:

  

package com.cxh.test1;import java.util.HashMap;import java.util.HashSet;import java.util.Set;class People{private String name;private int age;public People(String name,int age) {this.name = name;this.age = age;}public void setAge(int age){this.age = age;}@Overridepublic int hashCode() {// TODO Auto-generated method stubreturn name.hashCode()*37+age;}@Overridepublic boolean equals(Object obj) {// TODO Auto-generated method stubreturn this.name.equals(((People)obj).name) && this.age== ((People)obj).age;}}public class Main {public static void main(String[] args) {People p1 = new People("Jack", 12);System.out.println(p1.hashCode());HashMap<People, Integer> hashMap = new HashMap<People, Integer>();hashMap.put(p1, 1);p1.setAge(13);System.out.println(hashMap.get(p1));}}

The output result of this Code section is "null". The reason must be clear.

Therefore, when designing the hashCode and equals methods, if the data in the object is variable, it is best not to depend on this field in the equals and hashCode methods.

The above is my personal understanding. If there are any mistakes, please criticize and correct them.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.