Linkedhashmap inherited the HashMap, he added a two-way list structure on the basis of HashMap, the list is maintained by default key insertion order, the duplicate key value insertion does not change the order, for the user needs to return a sequence of the same map object case. You can also generate Access-order sequential versions, which are stored in the order of recent accesses, the nodes that have just been accessed are at the end of the list, and suitable for the lru,put get compute merge to count as one access, where a node with the same put key value counts as a single access. Replace is only one access when replacing a key-value pair, and the order of access generated by Putall depends on the iterator implementation of the original map.
When you insert a key-value pair, you can automatically delete the oldest key-value pair when inserting by using the Removeeldestentry override to implement the new key value pair
With the method provided by the HashMap, the iterator because is traversed by the bidirectional list, so the extra overhead is proportional to the size of the capacity independent, so the selection of the initial size of the traversal time of the increase is not hashmap serious, the latter of the traversal time dependence and capacity.
Also is a non-thread-safe method, for Linkedhashmap, to modify the structure of the operation in addition to increase and delete the key value of the external, and for Access-order when access causes the iterator order changes, mainly get operations, for the insertion Order, Just modifying the value of an existing key value is not an operation to modify the structure, but for the access order, the put and get existing key values change the order. Iterators are also fail-fast designed, but Fail-fast is just a debugging feature and a well-designed program should not have this error
Because HashMap joined TreeNode, so now Linkedhashmap has this function as well.
The linked list in the following description, if not specifically stated, refers to the Linkedhashmap doubly linked list
Take a look at the basic structure, each key-value pair joins the front and back pointers, the collection joins the tail-up pointer to form a doubly linked list, accessorder to indicate whether the linked list is stored in order of access or insert sequence
Static classEntry<k,v>extendsHashmap.node<k,v>{Entry<K,V> before, after;//added a pointer to form a doubly linked listEntry (intHash, K key, V value, node<k,v>next) { Super(hash, key, value, next); } } /*** The head (eldest) of the doubly linked list.*/ transientLinkedhashmap.entry<k,v>Head; /*** The tail (youngest) of the doubly linked list. Tail*/ transientLinkedhashmap.entry<k,v>tail; //true Access order false Insert order Final BooleanAccessorder;
Then there are several internal methods. Linknodelast connecting p to the tail of the list
Private void linknodelast (linkedhashmap.entry<k,v> p) { linkedhashmap.entry<K,V> last = tail; = p; if NULL ) = p; // If the linked list is empty then P is also the head Else { = last ; = p; } }
Transferlinks replacing SRC with DST
Private voidTransferlinks (linkedhashmap.entry<k,v>src, linkedhashmap.entry<K,V>DST) {Linkedhashmap.entry<K,V> b = Dst.before =Src.before; Linkedhashmap.entry<K,V> A = Dst.after =Src.after; if(b = =NULL) Head=DST; ElseB.after=DST; if(A = =NULL) Tail=DST; ElseA.before=DST; }
Reinitialize the head and tail are set to NULL based on the call to the HashMap method
void reinitialize () { Super. Reinitialize (); NULL ; }
NewNode generates a Linkedhashmap node, next points to E, and inserts to the end of the Linkedhashmap list
Node<k,v> newNode (int hash, K key, V value, node<k,v> e) { linkedhashmap.entry<k,v > P = new linkedhashmap.entry<k,v> (hash, key, value, e); Create a new key-value pair, next points to E linknodelast (p); p Insert to the end of the Linkedhashmap list return p; }
Replacementnode generates a LINKEDHASHMAP node to replace the original node based on the Origin node.
Node<k,v> Replacementnode (node<k,v> p, node<k,v> next) { linkedhashmap.entry<K,V > q = (linkedhashmap.entry<k,v>) p; Linkedhashmap.entry<K,V> t = new linkedhashmap.entry<k,v> (Q.hash, Q.key, Q.value, Next ); // generate a new key value pair Next is given next parameter Transferlinks (q, T); // Replace Q with T return t; }
Newtreenode generates a TreeNode node, next points to next, inserts to the end of the Linkedhashmap list
Treenode<k,v> newtreenode (int hash, K key, V value, node<k,v> next) { TreeNodeNew treenode<k,v> (hash, key, value, next); // generates a treenode,next pointing to the parameter next Linknodelast (P); // p insert to end of Linkedhashmap list return p; }
Replacementtreenode generates a new treenode,next based on the node p and sets it to the given next, replacing the original p
Treenode<k,v> Replacementtreenode (node<k,v> p, node<k,v> next) { linkedhashmap.entry <K,V> q = (linkedhashmap.entry<k,v>) p; TreeNodeNew treenode<k,v>(Q.hash, Q.key, Q.value, next); Transferlinks (q, t); // generate a new treenode,next based on the node p set to the given next, replacing the original P return t; }
Afternoderemoval removing nodes from the Linkedhashmap chain E
voidAfternoderemoval (node<k,v>e) {linkedhashmap.entry<K,V> p =(Linkedhashmap.entry<K,V>) E, B = p.before, a =P.after; P.before= P.after =NULL; if(b = =NULL) Head=A; ElseB.after=A; if(A = =NULL) Tail=b; ElseA.before=b; }
Afternodeinsertion may remove the oldest node, need evict to true while the linked list is not empty and removeeldestentry need to be rewritten
void afternodeinsertion (boolean evict) { linkedhashmap.entry<K,V> first ; ifnull && removeeldestentry (first)) {//removeeldestentry needs to be rewritten before it works, Otherwise it must return false K key = First.key; Remove the node of the linked list header nullfalsetrue); } }
Afternodeaccess after the visit, the node E is moved to the tail of the list, need map is access-order, if the move is successful increase modcount
voidAfternodeaccess (node<k,v>e) {linkedhashmap.entry<K,V>Last ; if(Accessorder && (last = tail)! = e) {//map is Access-order and E is not the tail of the list.Linkedhashmap.entry<k,v> p =(Linkedhashmap.entry<K,V>) E, B = p.before, a =P.after; P.after=NULL; if(b = =NULL)//Cut the node e from the linked list .Head =A; ElseB.after=A; if(A! =NULL) A.before=b; Else Last=b; if(Last = =NULL) Head=p; Else{P.before=Last ; Last.after=p; } Tail= P;//node E moves to the tail of the list.++modcount;//because there are access-order below the node is moved, so increase modcount } }
In terms of constructors, the Accessorder default is the insertion order, the initial size is 16, the load factor is 0.75, and this is the same as HashMap. The copy construct also calls the Hashmap.putmapentries method
The
Containsvalue iterates through the list looking for an equal value, and this operation must not cause a structural change
public boolean Containsvalue (Object value) { for (LINKEDHASHMAP.ENTRY<K,V&G T e = head; E! = null ; E = e.after) {// The check is also traversed according to the list of links provided by Linkedhashmap v v = E.value; if (v = = value | | (Value! = null && Value.equals (v))) return true ; return false ; }
The Get method uses the GetNode method of the HashMap, if the node is found and the map is the access order, the Access node is placed at the end of the list, and null is returned if it is not found. And Getordefault's only difference is that when it's not found, it returns defaultvalue
PublicV get (Object key) {Node<K,V>e; if(E = getnode (hash (key), key) = =NULL)//GetNode method for multiplexing HashMap return NULL; if(Accessorder) afternodeaccess (e);//put E at the end of the Access-order. returnE.value; } Publicv Getordefault (Object key, v DefaultValue) {Node<K,V>e; if(E = getnode (hash (key), key) = =NULL) returnDefaultValue;//The GetNode method for multiplexing HashMap returns defaultvalue if no corresponding node is found . if(Accessorder) afternodeaccess (e);//put E at the end of the Access-order. returnE.value; }
The Clear method sets head and tail to null on a hashmap basis
Public void Clear () { Super. Clear (); NULL ; }
Removeeldestentry is called when the put and Putall insert a key-value pair, the original must return FALSE, if you want to automatically delete the oldest key-value pair to return true, you need to rewrite. For example, the control size cannot exceed 100
Private Static Final int Max_entries = +; protected Boolean Removeeldestentry (map.entry eldest) { return size () > max_entries; }
The following two methods are similar to HashMap, which returns the set of key and the collection of value and the set of return key-value pairs, this is a direct reference, so modifications to their remove are directly fed back to Linkedhashmap
PublicSet<k>KeySet () {Set<K> KS =KeySet; if(KS = =NULL) {KS=NewLinkedkeyset (); KeySet=KS; } returnks//returns the set of the key value } PublicCollection<v>values () {Collection<V> vs =values; if(vs = =NULL) {vs=Newlinkedvalues (); Values=vs; } returnvs//returns a collection that contains all value values } PublicSet<map.entry<k,v>>EntrySet () {Set<Map.Entry<K,V>>es; return(es = entryset) = =NULL? (EntrySet =NewLinkedentryset ()): es;//returns a set containing all key-value pairs}
Checking the Putval method of HashMap, we can see that afternodeaccess is called when the same key value is found and the value is modified, and the node order is changed for Access-order
if NULL // The same key is found, the value is modified and the old value is returned. V oldValue = e.value; if NULL ) = value; Afternodeaccess (e); return oldValue; }