If anyone let me describe the working mechanism of Hash Map, I will answer simply: "Hash -based rules". This sentence is very simple, but before understanding this sentence, we must first understand what ish, isn't it?
What is a beh
Hash is simply a unique string obtained after the attribute of the variable/object is applied to a certain algorithm, and this string is used to determine the uniqueness of the variable/object. A correct hash function must abide by this criterion.
When the hash function is applied to the same object or an Equal object, each execution should return the same value. In other words, two equal objects should have the same hashcode.
Note: All Java objects inherit a default hashCode () method from the Object class. This method returns the address of the object in the memory as an integer. This is a good Hash implementation. He ensures that different objects have different hashcode.
One introduction to the ENTRY class
The definition of a map is: an object from a mapping key to value. Very simple, right?
Therefore, there must be a certain mechanism in HashMap to store these key values pairs. Make HashMap has an internal class Entry, which looks like this.
Static Class Entry <k, v> Implements Map.entry <k, v> {final k key; v value; entry <k, v> next; ... // more code goes here}
Of course, the ENTRY class has attributes to store key values. Key is marked by Final. In addition to Key and Value, we can also see two variables Next and Hash. Next we try to understand the meaning of these variables.
What does the put () method actually do?
Before looking at the implementation of the PUT method, it is necessary to take a look at the storage of the entry instance in the array. This is the definition in HashMap:
/ ** * the table, resize asilessary. Length must always be a power of two. */ Transient entry [] table now. /*** associates the Specified Value with the Specified Key in this map.* If the map previously containing for the key, the old* value is CED. ** @Param Key With Whit the Specified Value is to be associateed * @param value value to be associated with the specify key* @Return the previous value associated with </tt>, or* <TT> null </tt> if theer e /tt>.* (A <TT> NULL </tt> Return Can Also Indicate that the Map* Previously Association <TT> NULL </tt> Key </tt>.)*/Public v Put ( K key, value) {if (key == null) return putFornullkey (value); int hash = have (key.hashcode ()); int (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.RCORDACCESS (this); Return Oldvalue;}} modentry (have, key, all); Return null;}
Let us watch step by step
First of all, check whether the key is null. If the key is the position of the NULL value, because the HashCode of NULL is always 0
Next, this key's hash value is calculated through the KEY HashCode () method, which is used to calculate the position in the array of the ENTRY object. JDK's designer assumes that some people may write very poor hashcode () methods, and there will be some very large or very small hash values. To solve this problem, they introduced another hash function to accept the HashCode () of the object and convert it to the capacity of the array.
Next is the indexFor (hash, table, length) method, which calculates the accurate location of the Entry object storage.
Next is the main part. We all know that two different objects may have the same hashCode value. How can the two different objects store in the same position [called BUCKET]?
The answer is LinkedList. If you remember, the Entry class has a NEXT variable, this variable always points to the next variable in the chain, which fully meets the characteristics of the linked list.
Therefore, when a collision occurs, the Entry object will be stored in the form of a linked list. When an Entry object needs to be stored, HashMap checks whether the location has a ENTRY object. Check her NEXT attribute. If it is empty, the current Entry object is used as the next node of the ENTRY object that has been stored.
What if we save the existing Key in another value? Logically, the old value will be replaced. After detecting the storage position of the Entry object, HashMap will traverse the Entry linked list in that position. To each Entry call the EQUALS method, all the objects in this linked list have the same HashCode () and the Equals method. If you find that the Equals method is equal, the replacement is performed.
In this way, HashMap can ensure the uniqueness of the key.
The work mechanism of the get method
Now we have learned the mechanism of storage -paired in HashMap. The next question is: how to query the results from a HashMap.
In fact, the logic is the same as the PUT. If the passing KEY match is matched, return the value of the location. If not, return Null.
/*** Returns the value to which the specify key is mapped,* or {@code null} if this map contains no mapping for the key. ** <p> More Formalth, if this is map contains a mapping from a key* {@code k} to a value {@code v} such that {@code (key == null? K == null:* key.equals (k)}, then this method reTURNS {@code v}; o theerwise * It Return {@code null}. at the map contains No mapping for the key; it's also* posesible that the map explicitly maps the key to {@code null}.* The {@link #Containskey containskey} means May be used to* distinguish the two cases. ** @See #Put (Object, Object)*/Public V Get (Object Key) {if (key == NULL) Return GetFornullkey (); int Hash = Hash (key.hashcode ()); > 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;}
The above code looks similar to the put () method, except if (e.hash == Hash && ((k = e.Key) == key || key.equals (k))).
Pay attention