On the Hashcode method in Java (recommended) _java

Source: Internet
Author: User
Tags numeric numeric value stub

A hash table This data structure must be familiar to most people, and in many places, hash tables are used to improve search efficiency. There is a method in the Java object class:

 
 

According to the declaration of this method, the method returns a numeric value of type int and is a local method, so no specific implementation is given in the object class.

Why does the object class need such a method? How does it work? Today we will discuss the Hashcode method concretely.

I. The role of the Hashcode method

For a programming language that contains a container type, hashcode is basically involved. In Java, too, the main function of the Hashcode method is to work with a hash based collection, which includes HashSet, HashMap, and Hashtable.

Why do you say that? Consider a situation where you can determine whether an object already exists in the collection when you insert it into the collection. (Note: Duplicate elements are not allowed in the collection)

Perhaps most people would think of calling the Equals method to compare each one, which is really doable. But if there are 10,000 or more data in the set, if you use the Equals method to compare each one, efficiency is a problem. At this point the function of the Hashcode method is reflected, when the collection to add a new object, first call the object's Hashcode method, get the corresponding hashcode value, In fact, in the concrete implementation of HASHMAP will use a table to save the hashcode value of the object that has been saved, if the table does not have the hashcode value, it can be stored directly, no more comparisons; if the hashcode value exists, The Equals method that calls it is compared with the new element, the same words do not save, the same is the hash of other addresses, so there is a problem of conflict resolution, so the actual number of calls to the Equals method is greatly reduced, To be popular: The Hashcode method in Java is to map the object-related information (such as the object's storage address, the object's field, etc.) to a numeric value based on certain rules, which is called a hash. The following code is a concrete 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 a new element to the HashMap, which is known from the implementation of the method, calling the Hashcode method to get the hashcode value of the element, and then looking at whether the Hashcode value exists in the table. If present, call the Equals method to redefine whether the element exists and, if it exists, update the value, otherwise add the new element to the HashMap. It can be seen from here that the Hashcode method exists to reduce the number of calls to the Equals method, thus increasing the efficiency of the program.

Some friends mistakenly assume that by default, the Hashcode return is the object's storage address, in fact, this view is not comprehensive, it is true that some JVMs are implemented directly to return the object's storage address, but most of the time is not the case, can only say that there is a certain association of storage address. The following is the implementation of the hash hash value generated in the hotspot JVM:

Static inline intptr_t get_next_hash (Thread * Self, oop obj) {intptr_t value = 0;  if (hashcode = 0) {//This form uses a unguarded global park-miller RNG,//So it's possible for two threads to

   Race and generate the same RNG.

   On MP system We'll have lots of RW access to a global, so//mechanism induces lots of coherency traffic.

 Value = Os::random (); else if (hashcode = 1) {//This variation has the property of being stable (idempotent)//between STW Opera tions.

   This can is useful in some of the 1-0//synchronization schemes.

   intptr_t addrbits = intptr_t (obj) >> 3;

 Value = addrbits ^ (addrbits >> 5) ^ gvars.stwrandom;      else if (hashcode = = 2) {value = 1;

 For sensitivity testing} else if (Hashcode = 3) {value = ++gvars.hcsequence;

 else if (hashcode = = 4) {value = intptr_t (obj); else {//Marsaglia ' s xor-shift scheme with thread-specific state//is probably the best overall implementation--we'll//likely make this default in future releases.

   unsigned t = Self->_hashstatex;

   T ^= (t << 11);

   Self->_hashstatex = Self->_hashstatey;

   Self->_hashstatey = Self->_hashstatez;

   Self->_hashstatez = Self->_hashstatew;

   Unsigned v = self->_hashstatew;

   v = (v ^ (v >>)) ^ (t ^ (T >> 8));

   Self->_hashstatew = v;

 Value = V;

 } value &= Markoopdesc::hash_mask;

 if (value = = 0) value = 0xBAD;

 ASSERT (Value!= markoopdesc::no_hash, "invariant");

 Tevent (hashcode:generate);

return value; 

 }

The implementation is located under the Hotspot/src/share/vm/runtime/synchronizer.cpp file.

So one would say, can you tell whether two objects are equal directly based on the hashcode value? Certainly not, because different objects may generate the same hashcode value. Although it is not possible to judge whether two objects are equal according to the Hashcode value, two objects can be judged directly according to the Hashcode value, and two different objects must be equal if the hashcode values of two objects are unequal. If you want to determine whether two objects are really equal, you must pass the Equals method.

That is to say, for two objects, the hashcode value of the two objects must be equal if the result of the call Equals method is true;

If the Equals method results in False, the hashcode value of the two objects is not necessarily different;

If the hashcode value of two objects is unequal, the result of the Equals method must be false;

If the hashcode values of two objects are equal, the result of the Equals method is unknown.

Two. Equals Method and Hashcode method

In some cases, programmers need to rewrite the Equals method when designing a class, such as the string class, but it is important to note that the Hashcode method must be overridden while overriding the Equals method. Why do you say that?

Let's look at 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;

  }    

  @Override public

  boolean equals (Object obj) {

    //TODO auto-generated a stub return

    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");

    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"));

  }

 

Here I only rewrite the Equals method, and say that if the two people object, if its name and age are equal, it is considered the same person.

The original intention of this code is to think that the code output is "1", but it actually outputs "null." Why, then? The reason is to override the Equals method while forgetting to rewrite the Hashcode method.

Although by overriding the Equals method, the two objects with the same logical name and age are judged to be equal objects (similar to the String class), but you know by default the Hashcode method maps the storage addresses of the objects. It is not surprising that the output of the above code is "null". The reason is simple, P1 points to objects and

System.out.println (Hashmap.get ("Jack", 12)); The New people ("Jack", 12) generates two objects, and their storage addresses are definitely different. The following is a concrete implementation of the HashMap get method:

 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 get operations, because the resulting hashcdoe value is different (note that the above code may in some cases get the same hashcode value, but this probability is relatively small, Because although the same hashcode value can be obtained for different storage addresses of two objects, it causes the for loop to not execute in the GET method and returns null directly.

So if you want the above code output to be "1", it's simple to rewrite the Hashcode method so that the Equals method and the Hashcode method are always 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;

  @Override public int hashcode () {//TODO auto-generated a stub return Name.hashcode () *37+age; @Override public boolean equals (Object obj) {//TODO auto-generated a stub return this.name.equ

  ALS ((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)); }

} 

As a result, the output is "1".

The following passage is excerpted from the effective Java book:

During program execution, the Hashcode method must consistently return the same integer, as long as the information used in the comparison operation of the Equals method has not been modified, so that the same object is called multiple times.

If two objects are equal according to the Equals method, then the Hashcode method that calls two objects must return the same integer result.

If two objects are unequal according to the Equals method, the Hashcode method does not necessarily return a different integer.

The second and third articles are well understood, but the first one is often overlooked. The P495 page in the Java programming idea also has the same passage as the first one:

The most important factor in designing hashcode () is that whenever you call Hashcode () on the same object, you should produce the same value. If a Hashcdoe value is generated when an object is added to the HashMap with put (), and when fetched with a get (), another hashcode value is generated, and the object cannot be obtained. So if your Hashcode method relies on variable data in the object, the user should be careful because the hashcode () method generates a different hash code when the data changes.

Here's 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;

  @Override public int hashcode () {//TODO auto-generated a stub return Name.hashcode () *37+age; @Override public boolean equals (Object obj) {//TODO auto-generated a stub return this.name.equ

  ALS ((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 result of this code output is "null", presumably the reason why everyone should be clear.

Therefore, when designing the Hashcode method and the Equals method, if the data in the object is variable, it is best to not rely on the field in the Equals method and the Hashcode method.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

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.