Underlying Implementation of hashmap and underlying implementation of hashmap
The underlying implementation of HashMap is implemented by the array + linked list structure. To add, delete, and obtain elements, calculate the hash value based on the hash value and table. length calculates the index, that is, the subscript of the table array, and then performs the corresponding operation.
However, HashMap and HashTable use different methods to calculate hash:
HashMap directly modulo the table array length using the hashcode of the key, while HashMap performs two hash operations on the hashcode of the key to obtain better hash values, then, modulo the length of the table array.
Implementation of specific methods:
By default, HashMap creates an Entry array with a capacity of 16 during initialization. The default load factor is 0.75, and the critical value is 16*0.75;
public HashMap() { this.loadFactor = DEFAULT_LOAD_FACTOR; threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); table = new Entry[DEFAULT_INITIAL_CAPACITY]; init(); }
For the put method:
HashMap performs special processing on the null key, which is always placed at table [0 ].
In the put process, hash is calculated first and then hash and table are used. the length parameter is used to calculate the index value, and then the key is placed at the table [index] position. When table [index] already has other elements, a linked list is formed at the table [index] position, place the newly added elements in table [index]. The original elements are linked through the next Entry. This solves the hash conflict problem in the form of a linked list. When the number of elements reaches the critical value (capactiy * factor) the table array length is changed to table. length * 2;
For the get method:
Similarly, when the key is null, special processing will be performed to find the element whose key is null on the linked list of table [0 ].
In the get process, the hash is calculated first, and then the index value is calculated through the hash and table. length operations, and then the linked list on the table [index] is traversed until the key is found, and then the system returns
For the remove Method:
The remove method is similar to put get. Calculate the hash, calculate the index, traverse the search, and remove the elements from the table [index] linked list.
For the resize method:
The resize method is not made public in hashmap. This method achieves very important hashmap resizing. The specific process is: Create a table first. new table of length * 2, modify the critical value, and then calculate the hash value of the elements in the table and use hash and table. length * 2 re-calculate the index and put it into the new table. Note that the index is re-calculated using the hash of each element, instead of simply moving the index element of the original table to the corresponding position of the new table
For the containsKey method:
The containsKey method is to calculate the hash and then use the hash and table. length to obtain the index value. traverse the table [index] element to find whether the value contains the same key.
Simple MyHashMap:
Public class MyHashMap {// default initialization size 16 private static final int DEFAULT_INITIAL_CAPACITY = 16; // default load factor 0.75 private static final float DEFAULT_LOAD_FACTOR = 0.75f; // critical value private int threshold; // number of elements private int size; // Number of resizing Times private int resize; private HashEntry [] table; public MyHashMap () {table = new HashEntry [DEFAULT_INITIAL_CAPACITY]; threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD _ FACTOR); size = 0;} private int index (Object key) {// calculate the position of the key in the table based on the hashcode and table length modulo. return key. hashCode () % table. length;} public void put (Object key, Object value) {// when the key is null, special processing is required. To simplify the implementation, ignore the null value if (key = null) return; int index = index (key); // traverses the entry at the index position. If duplicate keys are found, the value of the corresponding entry is updated, and HashEntry entry = table [index] is returned. while (entry! = Null) {if (entry. getKey (). hashCode () = key. hashCode () & (entry. getKey () = key | entry. getKey (). equals (key) {entry. setValue (value); return;} entry = entry. getNext () ;}// if no entry is found at the index position or duplicate keys are not found, add (index, key, value) the new key to the index position of the table );} private void add (int index, Object key, Object value) {// place the new entry to the first position in the table index, if there is a value, the HashEntry entry = new HashEntry (key, value, ta Ble [index]); table [index] = entry; // determines whether the size has reached the critical value. If it has reached the threshold, scale up, double table capacicy if (size ++> = threshold) {resize (table. length * 2) ;}} private void resize (int capacity) {if (capacity <= table. length) return; HashEntry [] newTable = new HashEntry [capacity]; // traverses the original table and recalculates each entry into the newTable for (int I = 0; I <table. length; I ++) {HashEntry old = table [I]; while (old! = Null) {HashEntry next = old. getNext (); int index = index (old. getKey (); old. setNext (newTable [index]); newTable [index] = old; old = next; }}// use newTable to replace table = newTable; // modify the critical value threshold = (int) (table. length * DEFAULT_LOAD_FACTOR); resize ++;} public Object get (Object key) {// simplify processing here, ignore null value if (key = null) return null; hashEntry entry = getEntry (key); return entry = null? Null: entry. getValue ();} public HashEntry getEntry (Object key) {HashEntry entry = table [index (key)]; while (entry! = Null) {if (entry. getKey (). hashCode () = key. hashCode () & (entry. getKey () = key | entry. getKey (). equals (key) {return entry;} entry = entry. getNext () ;}return null;} public void remove (Object key) {if (key = null) return; int index = index (key); HashEntry pre = null; hashEntry entry = table [index]; while (entry! = Null) {if (entry. getKey (). hashCode () = key. hashCode () & (entry. getKey () = key | entry. getKey (). equals (key) {if (pre = null) table [index] = entry. getNext (); else pre. setNext (entry. getNext (); // if it is successfully found and deleted, modify size --; return;} pre = entry; entry = entry. getNext () ;}} public boolean containsKey (Object key) {if (key = null) return false; return getEntry (key )! = Null;} public int size () {return this. size;} public void clear () {for (int I = 0; I <table. length; I ++) {table [I] = null;} this. size = 0 ;}@ Override public String toString () {StringBuilder sb = new StringBuilder (); sb. append (String. format ("size: % s capacity: % s resize: % s \ n", size, table. length, resize); for (HashEntry entry: table) {while (entry! = Null) {sb. append (entry. getKey () + ":" + entry. getValue () + "\ n"); entry = entry. getNext () ;}} return sb. toString () ;}} class HashEntry {private final Object key; private Object value; private HashEntry next; public HashEntry (Object key, Object value, HashEntry next) {this. key = key; this. value = value; this. next = next;} public Object getKey () {return key;} public Object getValue () {return value;} public void setValue (Object value) {this. value = value;} public HashEntry getNext () {return next;} public void setNext (HashEntry next) {this. next = next ;}}