The first thing we need to do is tap code to implement HashMap, so what is HashMap? What is the data structure? What is the underlying principle?
What is i hashMap?
We all know that hashMap, a storage unit that stores data as key s and value s, should also be used in projects. And hashMap is an out-of-order storage structure, so why is it out of order?
ii HashMap data structure (advantages and disadvantages of arrays and chained lists are in the article on the differences between ArrayList and LInkedList)
JDK7: Array + Chain List
JDK8: Array + Chain List + Red-Black Tree
I believe that many people who have seen the interview also know this. The implementation of our code tapping today is based on JDK7. There is also a point after JDK8.
HashMap is a storage tool that specifies a length of 16 (the length of an array in HashMap). The common method we use in HashMap is put and get Method.
iii Bottom Principles
1.put method
Just now we mentioned that HashMap is an out-of-order storage structure with an array length of only 16, so how does HashMap implement the put method? Bullshit doesn't go too far. It works directly:
First the HashMap put method calculates the remainder of the corresponding hash value of 16 (forced into the int type) using the key value you pass in [it may be more complicated to calculate hashMap, but that's the basic principle], which we call index, and then the HashMap put method uses this index value to determine where to store the data in the array labeled index. So where is the list? Because the index we get is divided by the remainder of 16, there must be duplicate index values, and there will be hash conflicts. The way to avoid hash conflicts is to introduce a chain table. When we find that the index values are duplicated, HashMap replaces the existing values in the array with the values that will be stored and points to the existing values. That might be one-sided, so let me show you in the form of a picture: (The number in the picture is just for ease of understanding, not an actual array or list number)
Assuming this is an array of sixteen lengths, I'm going to store some data first, a pair of Key s and Value s.
The hash value is the hash value that we computed, followed by the key and value, but now if you have another value to store to 3, this creates a hash conflict and you need to introduce a chain table. (Regardless of what next is, it will be next, look down)
Now save another value, if his hash:12587, key:Map Value: Map interface, what should I do if this value is also calculated to be saved to position 3 in the diagram? (One more b, I don't want to change it. Just look at it like this, without compromising my understanding.)
Now we see that the next value in 3 is the key value of the second element in the list, so HashMap resolves the hash conflict. This is one of the logic of HashMap's put method. (Red-Black Tree was introduced in JDK8, which automatically converts to Red-Black Tree storage when the chain table data is greater than 8)
2 HashMap get method
After the put method, let's talk about the get method
hashMap's get method logic is also simple, first by calculating the hash value to find the corresponding location of the array, and then to determine if the key value is equal to the value stored in the array, equality returns the value, inequality returns the value, inequality determines whether the key in the next is empty, not empty, and then the key in the next node is equal until equality returns, or returns empty.
HashMap get, put method principle is finished, let's use code to implement it
iiii Code Implementation (JDK7)
First, we create a Map interface that defines get, put, and size methods.
An Entry interface is defined inside to standardize the format of our Map.
package com.guozm.waimai1.hashmap; //Define a map class public interface Map<K,V> { //Define put method V put(K k,V v); //Define the gat method V get(K k); //Define size int size(); interface Entry<K,V>{ Object getKey(); Object getValue(); } }
Then define a HashMap, Entry class to implement Map, Entry class methods (including methods to calculate index and find key s recursively) there are comments in the code that can be viewed.
package com.guozm.waimai1.hashmap; //Map Implementation Class public class HashMap<K,V> implements Map<K,V> { //Create Array Object private Entry table[] = null; //Initialize size int size = 0; //Construction method public HashMap() { //hashMap array capacity is 16 table = new Entry[16]; } /*** * 1.hash operation with key * 2.Get index-->array subscript--->object corresponding to array--->Entry * 3.To determine if the current object is empty, empty: you can store the data directly, not empty: hash conflict * 4.Chain list is required to resolve hash conflicts * 5.Return Stored Results * @param k * @param v * @return */ @Override public V put(K k,V v) { //Get hash by calculating int index = hash(k); //Get the object under the current array subscript Entry entry = table[index]; //Determine if the current object contains data if (entry == null){ //Insert data into the array at the index position table[index] = new Entry<K,V>(k,v,index,null); //size+1 for each additional data size++; }else{ //Store inside the old data method next table[index] = new Entry<K,V>(k,v,index,entry); } return (V) table[index].getValue(); } /*** * Method of calculating array subscripts by passing in key value * @param k * @return */ private int hash(K k) { int i = k.hashCode()%16; if (i >= 0){ return i; }else{ return -i; } } /*** * 1.hash with key to calculate array subscript index * 2.Find entry object by index * 3.Determine whether the entry object is empty or not: Return directly without finding the corresponding data * 4.Not empty: Determines if the key is equal to the key in the object: returns value * 5.Unequal: Determine whether the next is empty, or if not, whether the key in the next is equal to the key to be found until it is equal before returning or empty * @param k * @return */ @Override public V get(K k) { //First determine if there is any data in the map if(size == 0){ //Return empty if not saved return null; } //Get the subscript, index value by hash algorithm int index = hash(k); //Find a matching entry value using the findValue method Entry<K,V> entry = findValue(table[index] , k); //Determine if the entry value is empty if(entry != null){ //Return Value return (V) entry.getValue(); } return null; } /*** * Recursively implementing a chain table to find entry objects that meet the requirements * Otherwise, an entry object is returned * Irregular returns null * @param entry * @param k * @return */ private Entry<K,V> findValue(Entry<K,V> entry ,K k) { //Determine if k is equal to the key value in the entry object if (k.equals(entry.getKey())|| k == entry.getKey()){ //Equality returns directly return entry; //Otherwise execute else }else { //Determine if the list also contains data if (entry.next != null){ //Recursively find values that match return findValue(entry.next,k); } } return null; } @Override public int size() { return size; } //Entry Implementation Class class Entry<K,V> implements Map.Entry<K,V>{ //key K k; //value V v; //Computed hash value (index) int hash; //Pointer Entry<K,V> next; //Parametric construction method public Entry(K k, V v, int hash, Entry<K, V> next) { this.k = k; this.v = v; this.hash = hash; this.next = next; } @Override public Object getKey() { return k; } @Override public Object getValue() { return v; } } }
Finally, build a test class to test our HashMap put and get Method
package com.guozm.waimai1.hashmap; //Test Class public class HashTest { //Main method public static void main(String[] args) { Map<String,String> map = new HashMap<>(); map.put("Map","Map Interface"); map.put("HashMap","Realization Map Interface"); map.put("HashTest","Map Test Class"); System.out.println(map.get("Map")); System.out.println(map.get("HashMap")); System.out.println(map.get("HashTest")); System.out.println(map.getSize); } }
Run Results
Here we have written a simple HashMap.
Why iiii JDK8 Introduced Red and Black Trees
If we have a lot of data, after all, HashMap is only 16 sizes, there will be a lot of data under an index, that is, the chain length will be very long, when we want to find data in the chain table, we have to traverse the entire chain table. Time efficiency is low. So adding red and black trees to JDK8 is to optimize this. (Personal understanding, welcome communication if there are any errors)