HashMap of stored data rules

1, through Hash algorithm to understand the target efficiency HashMap

         We first review the data structure of a knowledge point: at a length of n (suppose 10,000) linear table (assuming that is ArrayList), the digital storage of the disorder; if we are looking for a specified number, you would have by traversing sequentially from beginning to end to find, such as the average search frequency is divided by 2 n (here 5000).

         Let us observe Hash table (Hash table here is purely conceptual data structures, and Java has nothing to do). Its average search times close to 1, the cost is quite small, the key is in the Hash table, stored therein data and its storage location is associated with the Hash function.

        We assume a Hash function is x * x% 5. Of course, in reality impossible to use such a simple Hash function, we are here purely for convenience of explanation, while the Hash table is a linear table length is 11. 6 If we want to put into it, then we will first use 6 Hash function calculation, the result is 1, so we'll put the index number is 6 1 this position. Similarly, if we want to put the number 7, after Hash function calculation, the result is 7 4, it will be included in the index is the position 4. The results as shown in FIG.

      The benefit of this is obvious. For instance, we find from 6 in this element, we can index calculated by the position 6 of the first Hash function, and then find it directly from No. 1 in the index.

     However, we encounter the "Hash values ​​conflict," this issue. After such calculation Hash function, 7 and 8 have the same Hash value, which uses the Java HashMap object is "strand address method" solution. Results as shown below.

 

      Specific approach is for all Hash value is an object i build a synonym list. Suppose we put the time in 8 Discovery 4 position has been accounted for, it will create a new node into the linked list 8. Similarly, if we are looking for 8, then No. 4 found in the index instead of 8, and that will in turn look down the list.

      Although we still can not completely avoid the problem of conflict of Hash values, but Hash function design is reasonable, it can still ensure a synonym list length is controlled in a reasonable range. Speaking of theoretical knowledge are not random, we can clearly understand the importance rewrite hashCode method in later years.

2, why should override equals and hashCode methods

    When we deposit a custom class with a HashMap, if they do not override the equals and hashCode methods from the class definition, and the result will be not the same as we expected. We look WithoutHashCode.java this example.

     We define a Key class; in which defines a unique attribute id. Currently we first commented equals and hashCode methods.    

import java.util.HashMap;

class Key {

    private Integer id;

    public Integer getId() {
        return id; 
    }

    public Key(Integer id) {
        this.id = id; 
    }

    //故意先注释掉equals和hashCode方法
    // public boolean equals(Object o) {
    //     if (o == null || !(o instanceof Key)) {
    //          return false; 
    //     } else {
    //          return this.getId().equals(((Key) o).getId());
    //     }
    // }

    // public int hashCode() { 
    //    return id.hashCode();
    // }
 }

 public class WithoutHashCode {

     public static void main(String[] args) {

         Key k1 = new Key(1);
         Key k2 = new Key(1);

         HashMap<Key,String> hm = new HashMap<Key,String>();
         hm.put(k1, "Key with id is 1");

         System.out.println(hm.get(k2));
     }
 }

In the main function, we define two Key objects whose id is 1, like they are the same two keys can open the same door.

We have created a HashMap object by generics. It can store the object key portion Key type, value, may be stored in an object of type String.

We put the method k1 and a string of characters to put in hm; k2 and we want to get value from HashMap in; It's like we want to use this key to lock the door k1, k2 used to open the door. This is logical, but the current results, that string returns the result is not what we imagined, but null.

There are two reasons for the method is not overridden. The first is not override hashCode method, there is no override equals the second method .

When we put k1 to HashMap, the hashCode method first calls the Key of this class compute its hash value, then put into the hash value of k1 guided by the memory location.

The key is we do not define the hashCode method Key in. Here still call the hashCode method (all classes are subclasses of Object) Object class, and the class Object hashCode method returns the hash value is actually a memory address k1 object (assumed to be 1000).

If we followed calls hm.get (k1), then we will call again hashCode method (k1 or return address of 1000), then in accordance with the hash value obtained k1 can be found quickly.

But here's the code we are hm.get (k2), when we call the hashCode method of the Object class when (as in not defined Key) calculated hash value k2, in fact, get the memory address of k2 (assumed to be 2000). Since k1 and k2 are two different objects, they will not be the same memory address, which means that their hash values ​​must be different, that's the reason we can not get with the hash value of k1 and k2.

When we removed the annotation hashCode method, you will find that it is the return value of the id attribute hashCode, where k1 and k2 are the id of 1, so their hash values ​​are equal.

Let us correct what kept k1 and k2 take action. When deposit k1, based on the hash value of its id, is assumed 100 here, k1 object into the corresponding position. While taking k2, it is to calculate a hash value (k2 because the id is 1, this value is 100), then go to this position.

But the result will be our surprise: No. 100 position obviously has k1, but the output line 26 is still null. The reason is that no object equals method Key rewrite.

HashMap is treated by the conflict chain address method, that is, at positions 100, there may exist a plurality of objects stored in a linked list. They returned by the hash values ​​are 100 hashCode method.

When we look through the hashCode to 100 position of k2, does get k1. But k1 and k2 is possible only with the same hash value, but not necessarily equal, and k2 (k1 and k2 two keys may not be able to open the same door), this time, we need to call the equals method Key object to determine whether the two the equal.

Since we do not define the equals method in Key object, the system would have to call the equals method of the Object class. Due to the inherent method of Object is judged according to the memory address of the two objects, so k1 and k2 will not be equal, which is why the reasons still continues to receive null by hm.get (k2).

To solve this problem, we need to open the note equals method. In this method, as long as the two objects are Key type and their id equal, they are equal.

3, description of the interview questions

Since the project was often used HashMap, so I will ask this question during the interview: Have you ever had to rewrite hashCode method? Did you rewrite hashCode and equals method when using HashMap? How do you write?

If you want the object HashMap's "key" section contain custom, be sure to use this object in its own way to override equals and hashCode Object in the method of the same name.

Published 13 original articles · won praise 1 · views 7798

Guess you like

Origin blog.csdn.net/weixin_40482816/article/details/105069561