A brief analysis of Java map source code

Source: Internet
Author: User
Tags int size concurrentmodificationexception

Map is a key-value pair and is a common data structure. The map interface defines the basic behavior of the map, including the most central get and put operations, and the method of defining this interface is shown in the following:


There are different map implementations in the JDK that apply to different scenarios, such as thread-safe hashtable and non-thread-safe hashmap.

As a subclass of the map interface in the JDK UML class diagram, there is a special case dictionary is not recommended:


The methods we need to focus on in the map interface are get, put, and iterator-related methods such as EntrySet (), KeySet (), and the values () method.

Entry

Before starting to analyze the map, first understand the storage of the elements in the map, we know that map can be considered as a set of key-value pairs, Java map using entry store key value pairs, this is an interface, which is defined as follows, simple and clear, the interface method is mainly to operate on the keys and values.

Interface Entry<k,v> {       K getKey ();     V GetValue ();    V SetValue (v value);     Boolean equals (Object O);     int hashcode ();    }

Abstractmap

The abstract implementation of the map interface is shown in the following example implementation code:

map<string,string> A =/** * * Abstract map implementation schematic, according to the document, and the list interface and its similar.        * *map is divided into variable and immutable two, immutable only implement the EntrySet method, and the returned set iterator cannot support the modification operation. * * variable map, need to implement put method, and then EntrySet iterator also need to support the modification operation * * *abstractmap inside the map is implemented, but its efficiency is difficult to say, such as its Get method used by the party        Law EntrySet. * * Usually subclasses are covered in a more efficient way. such as HashMap, keyset, values, get method, etc. */new abstractmap<string,string> () {/* * return MA            The collection of elements in P, the returned collection usually inherits Abstractset. */@Override public set<map.entry<string, string>> EntrySet () {return new Ab Stractset<map.entry<string,string>> () {@Override public iterator<java.u Til.                  Map.entry<string, String>> iterator () {return null;                  } @Override public int size () {return 0;           }              };               }      /* * The default implementation throws an exception, the variable map needs to implement this method */@Override public string put (string key, Stri           Ng value) {return null; }                 };

HashMap

HashMap inherits Abstractmap, is quite common data structure, uses the idea of hash hash, can insert and obtain data in the time Complexity of O (1). Its basic implementation can analyze the abstract methods in the previous section, the article

Analysis on the implementation and performance of HashMap the implementation of HashMap, put and get operations are described in more detail. The key to this is to look at his iterator implementation, where only the EntrySet () method is analyzed, and the keyset () and the values () method are same strain.

For an iterator, see the partial source code and related comments below:

/** * Returns a collection of all key-value pairs in the Map, used to traverse */public set<map.entry<k,v>> EntrySet () {return Entry        Set0 ();         }/** * Deferred initialization, built only when used.            * * the values () and KeySet () methods also use a similar mechanism */private set<map.entry<k,v>> entrySet0 () {            set<map.entry<k,v>> es = EntrySet; return ES! = null?        Es: (entryset = new EntrySet ());         }/** * True Enteryset is an internal class whose key implementation is an iterator implementation.         * * the values () and KeySet () methods also correspond to the corresponding inner classes. * Corresponding to the implementation of their own iterators.            The key is this iterator * */private Final class EntrySet extends Abstractset<map.entry<k,v>> {            Public iterator<map.entry<k,v>> Iterator () {return newentryiterator (); } public boolean contains (Object o) {if (!) (                o instanceof Map.entry)) return false; Map.entry<k,v> e = (map.entry<k,v>) o;                entry<k,v> candidate = Getentry (E.getkey ());            return candidate! = null && candidate.equals (e);            The public boolean remove (Object o) {return removemapping (o) = null;            } public int size () {return size;            } public void Clear () {HashMap.this.clear ();         }}/** * EntrySet iterator, inherits Hashiterator, implements next method.         * The values () and KeySet () methods, which are also inherited hashiterator, are different from the method of implementing next, * * can be compared. * * Key is hashiterator * * */private Final class Entryiterator extends hashiterator& Lt            map.entry<k,v>> {public map.entry<k,v> next () {return nextentry (); }}/** * *keyset () corresponding iterator */private final class Keyiterator extends H         ashiterator<k> {   Public K Next () {return nextentry (). GetKey (); }}/** * * HashMap entryset () KeySet () Universal iterator for VALUES () */Priva   TE Abstract class Hashiterator<e> implements iterator<e> {entry<k,v> next; Next entry to return int expectedmodcount;     for Fast-fail int index;   Current slots entry<k,v> current;                Current Entry Hashiterator () {expectedmodcount = Modcount;                    if (Size > 0) {//advance to first entry entry[] t = table; At the time of construction, find the first non-nullable array element in the array, namely the entry linked list, see//I am in front of the blog while (Index < T.le                Ngth && (next = t[index++]) = = null);            }} public Final Boolean hasnext () {return next! = NULL;  }             /**           * Key implementation, easy to understand, look for next, and construct the same time as the iterator */FINAL entry<k,v> nextentry () {                if (modcount! = expectedmodcount) throw new Concurrentmodificationexception ();                Entry<k,v> e = next;                 if (E = = null) throw new Nosuchelementexception ();                    if (next = e.next) = = null) {entry[] t = table;                while (Index < t.length && (next = t[index++]) = = null);                } current = e;            return e; } public void Remove () {if (current = = null) throw new Illegalstateexceptio                N ();                if (modcount! = expectedmodcount) throw new Concurrentmodificationexception ();                Object k = Current.key;                current = null;                HashMap.this.removeEntryForKey (k); ExpeCtedmodcount = Modcount; }         }

HashTable

The implementation is basically consistent with HashMap, except that the synchronous operation is added to the method. It can be used in a multithreaded environment. But now there is a concurrenthashmap, in high concurrency, you can use it to replace the Hashtable.

Linkedhashmap

HashMap may not conform to the requirements in some scenarios, because the elements put into them are unordered. and Linkedhashmap to some extent to solve this problem.

It inherits the HashMap on the implementation, expands the Haspmap.enteyset on the storage, joins the before, after fields, and connects the HASHMAP elements with the doubly linked list. This doubly linked list determines the order in which it is traversed. The order is usually inserted in the order of the map, but it has a field accessorder when True, the traversal order will be the LRU effect.

To study its order, we can start with the Put method, the Get method and the traversal method, first we look at the Get method:

/**         * Calls the Getentry method of the parent class directly. The key is         *  e.recordaccess (This) code * * * Public        V get (Object key) {            entry<k,v> e = (entry<k,v >) getentry (key);            if (E = = null)                return null;            E.recordaccess (this);            return e.value;        }               /**         * Entry.recordaccess Method         *         * If the order of Access (accessorder=true), then put it in the next position of the head node         * Otherwise do nothing,         * This allows you to determine the order of traversal based on the initial Accessorder property.         */        void recordaccess (hashmap<k,v> m) {            linkedhashmap<k,v> lm = (linkedhashmap<k,v> ) m;            if (lm.accessorder) {                lm.modcount++;                Remove ();                Addbefore (Lm.header);            }        }


Put method:

The/** * Put method calls this method, overriding the implementation in the parent class, */void addentry (int hash,k key, V value, int bucketindex) {             Createentry (hash, key, value, Bucketindex);             Remove eldest entry if instructed, else grow capacity if appropriate entry<k,v> eldest = Header.after; Callback.            If it is necessary to remove the newest element in the old element, the tail of the list.            if (Removeeldestentry (eldest)) {Removeentryforkey (Eldest.key);            } else {if (size >= threshold) Resize (2 * table.length);            }}/** * */void Createentry (int hash,k key, V value, int bucketindex) {       hashmap.entry<k,v> old = Table[bucketindex];            entry<k,v> e = new entry<k,v> (hash, key, value, old);            Table[bucketindex] = e;            The essence is to insert the end of the doubly linked list E.addbefore (header);        size++; }/** * is inserted in front of the existingentry because it is a doubly linked list. When Existingentry is HeaDer, * equivalent to inserting into the linked list at the end.            * */private void Addbefore (Entry<k,v> existingentry) {after = Existingentry;            before = Existingentry.before;            Before.after = this;        After.before = this; }


Iterating through the iterative interface directly using a doubly linked list, here do not repeat, you can see the source code is easy to understand. Note that the implementation of the listing overrides the related build iterator method in the parent class.

TreeMap and Currenthashmap can open a separate article to analyze. Here's a brief. TreeMap is based on a B-tree map, sorted by key. Currenthashmap is a powerful class in concurrent packages that is suitable for multithreading with high concurrency when data is read and written.

A brief analysis of Java map source code

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.