Java collection of HashMap source code implementation analysis

Source: Internet
Author: User

1. Introduction

We know from the above essay that the bottom of hashset is implemented by map, so what is map? How is the bottom layer implemented? Here we analyze the source code, to see the specific structure and implementation. The Map collection class is used to store element pairs (called "Keys" and "values"), where each key is mapped to a value. Map.entry is its inner class, which describes the key/value pairs in the map. It should be noted that the map, which allows NULL for a key, also allows null values. Its implementation is mainly HashMap and SortedMap, where SortedMap expands the map to keep the keys in ascending order, below we briefly analyze the implementation of HASHMAP. First, give an example of the application:

  

Package Com.test.collections;import Java.util.collection;import Java.util.hashmap;import java.util.Map;import  Java.util.set;public class Hashmaptest {/** * @param args */public static void main (string[] args) {//TODO auto-generated Method stubmap<string,string> map = new hashmap<string,string> (), Map.put ("A", "a"), Map.put ("D", "D"); Map.put ("S", "s"), Map.put ("C", "C"), Map.put ("B", "B"), Map.put ("W", "w"); System.out.println (Map.size ()); System.out.println (Map.isempty ()); System.out.println (Map.containskey ("a"));//booleansystem.out.println (Map.containsvalue ("a")); /booleansystem.out.println (Map.get ("A")); System.out.println (Map.Remove ("A")); Map.putall (map); set<string> KeySet = Map.keyset (); collection<string>  values = Map.values (); set<map.entry<string, string>> Entry = Map.entryset (); Map.clear ();}}
2. Inheritance structure

HashMap directly inherits the Abstractmap class, implements the Map<k,v>, cloneable, serializable interface, in addition to these inheritance and implementation, it also has some important property values. Simply look at:

Default_initial_capacity: Default initialization capacity (16);

Maximum_capacity: Maximum allowable capacity (1 << 30);

Default_load_factor: The default load factor (0.75);

Entry[] Table: stores the specific values.

transient int size: Records the size of the map.

Final float loadfactor: Load factor.

What does this mean in addition to a entry type in the above attribute? Originally this is the maintenance map key value class, used to store the map's specific value, let us look at its concrete implementation structure:

 Static Class Entry<k,v> implements Map.entry<k,v> {final K key;        V value;        Entry<k,v> Next;        final int hash;         /** * Creates new entry.            */Entry (int h, K K, v V, entry<k,v> N) {value = V;            Next = n;            key = k;        hash = h;        } Public final K GetKey () {return key;        Public final V GetValue () {return value;            Public final V SetValue (v newvalue) {v oldValue = value;            value = newvalue;        return oldValue; The public final Boolean equals (Object o) {if (!) (            o instanceof Map.entry)) return false;            Map.entry e = (map.entry) o;            Object K1 = GetKey ();            Object K2 = E.getkey (); if (k1 = = K2 | | (K1! = null && k1.equals (K2)))                {Object V1 = GetValue ();          Object v2 = E.getvalue ();      if (v1 = = V2 | |                    (V1! = null && v1.equals (v2)))            return true;        } return false; } public final int hashcode () {return (key==null? 0:key.hashcode ()) ^ (Value==nu ll?        0:value.hashcode ());        Public final String toString () {return GetKey () + "=" + GetValue (); }/** * This method is invoked whenever the value of a entry is * overwritten by an invocation of         Put (K,V) for a key k that's already * in the HASHMAP. */void Recordaccess (hashmap<k,v> m) {}/** * This method is invoked whenever the ENTR         Y is * removed from the table. */void Recordremoval (hashmap<k,v> m) {}}

Entry<k,v> implements the internal interface in the map interface Map.entry<k,v>,key,value is used to store the key value, entry<k,v> next also points to the next node pointer, Indicates that the storage space of map is not contiguous and can be dispersed. The hash attribute indicates that the position of the key is calculated based on the hash value. It is important to note that this occurs as an inner class of hashmap. In addition there are internal classes keyset,values, EntrySet, Valueiterator, Keyiterator, entryiterator but you can know their specific role through the class name.

3. Source code resolution A: constructors

  

Public HashMap (int initialcapacity, float loadfactor) {if (Initialcapacity < 0) throw new Illegalarg        Umentexception ("Illegal initial capacity:" + initialcapacity);        if (initialcapacity > maximum_capacity) initialcapacity = maximum_capacity; if (loadfactor <= 0 | |                                               Float.isnan (Loadfactor)) throw new IllegalArgumentException ("Illegal load factor:" +        Loadfactor);        Find a power of 2 >= initialcapacity int capacity = 1;        while (capacity < initialcapacity) capacity <<= 1;        This.loadfactor = Loadfactor;        threshold = (int) (capacity * loadfactor);        Table = new Entry[capacity];    Init ();    }public HashMap (int initialcapacity) {This (initialcapacity, default_load_factor);        } public HashMap () {this.loadfactor = Default_load_factor; threshold = (int) (DEFault_initial_capacity * default_load_factor);        Table = new Entry[default_initial_capacity];    Init (); } public HashMap (MAP&LT;. extends K,? extends v> m) {This (Math.max (int) (M.size ()/default_load_factor) +        1, default_initial_capacity), default_load_factor);    Putallforcreate (m); } void Init () {} private void putallforcreate (map<? extends K,? extends v> m) {for (iterator<? ext Ends Map.entry<? Extends K,? Extends v>> i = M.entryset (). iterator (); I.hasnext ();            {map.entry<? extends K,? extends v> e = I.next ();        Putforcreate (E.getkey (), E.getvalue ()); }    }

The construction method only needs to explain the first one, the other is to pass some default parameter values and then call the first construction method to implement the specific operation. Focus on the first method of construction. It first determines whether the incoming capacity is legitimate and whether the loading factor is legitimate. If the capacity operation maximum value is to be reset, but if the value passed in is negative, the exception is thrown. Then, according to the product of capacity and loading factor, the threshold value is obtained and assigned to the attribute threshold, then the storage space is allocated through table = new Entry[capacity], and the construction process is completed. The Init () method is empty and does not know what to do.

2.hash (int h)

  

static int hash (int h) {        //This function ensures, hashcodes that differ-only to        //constant multiples at each Bit position has a bounded        //number of collisions (approximately 8 at default load factor).        H ^= (H >>>) ^ (h >>> N);        Return h ^ (H >>> 7) ^ (H >>> 4);    }

The position of the key is determined based on the hash value, and if NULL is passed in, the hash value returned is 0, and the index value is 0.

3.size (), IsEmpty ()
   public int size () {        return size;    }    /**     * Returns <tt>true</tt> If this map contains no key-value mappings.     *     * @return <tt>true</tt> If this map contains no key-value mappings     *    /public boolean isEmpty () {        return size = = 0;    }

The map size is the value that returns the property value size directly, and whether it is null or empty if size is 0.

4.get (Object)
    Public V get (Object key) {        if (key = = null)            return Getfornullkey ();        int hash = hash (Key.hashcode ());        for (entry<k,v> 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;    }

Returns the corresponding value according to the key, first to determine whether the key is null, if it is empty, call Getfornullkey () returns the null key corresponding to the value of only one. In fact, it is the first value to return the map because null corresponds to a hash value of 0, the storage location is the first. Then call the hash () method to return a unique hash value, and then loop through the map, if the hash value is found to be equal to return its value directly, if no corresponding value is found to return null.

5.containsKey (Object)
   public boolean ContainsKey (Object key) {        return getentry (key)! = null;    }    Final entry<k,v> getentry (Object key) {        int hash = (key = = null)? 0:hash (Key.hashcode ());        for (entry<k,v> e = table[indexfor (hash, table.length)];             E! = null;             E = e.next) {            Object k;            if (E.hash = = Hash &&                (k = e.key) = = Key | | (Key! = null && key.equals (k)                ))) return e;        }        return null;    }

Determining if a value is included is the first to get the value, and if the obtained value is not empty, the object is present. The method to get the key is implemented according to the Getkey () method. First gets the hash value, then loops through the entry array and returns NULL if it encounters the same key.

6.put (K,V)
    Public V put (K key, V value) {if (key = = null) return Putfornullkey (value);        int hash = hash (Key.hashcode ());        int i = indexfor (hash, table.length);            for (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.recordaccess (this);            return oldValue;        }} modcount++;        AddEntry (hash, key, value, I);    return null;        } void AddEntry (int hash, K key, V value, int bucketindex) {entry<k,v> e = Table[bucketindex];        Table[bucketindex] = new entry<k,v> (hash, key, value, E);    if (size++ >= threshold) Resize (2 * table.length);        } void Resize (int newcapacity) {entry[] oldtable = table;        int oldcapacity = Oldtable.length; if (oldcapacity = = maximum_capacity) {            threshold = Integer.max_value;        Return        } entry[] newtable = new Entry[newcapacity];        Transfer (newtable);        Table = newtable;    threshold = (int) (newcapacity * loadfactor); }

We use the put (K,v) method to add the object to the map, first to determine whether the passed key is null, and if NULL, call the Putfornullkey (value) method to correspond to the value of the null key. If it is not empty, first get the hash value of K, and then loop the map, if the value already exists on the update overwrite value and return the old value, otherwise call addentry (hash, key, value, i), insert the new value. Insert and very simple, new a entry object and then determine the array position to specify the value.

4. Other

The implementation of the HASHMAP is not synchronous, which means it is not thread-safe. Both its key and value can be null. In addition, the mappings in HashMap are not ordered. An instance of HashMap has two parameters that affect its performance: initial capacity and load factor. Capacity is the amount of data in the hash table, and the initial capacity is just the capacity at the time of creation of the Hashtable. A load factor is a scale that a hash table can achieve before its capacity increases automatically. When the number of entries in the hash table exceeds the product of the load factor and the current capacity, then the Hashtable is rehash (that is, rebuilding the internal data structure), so that the Hashtable will have approximately twice times the number.

Java collection of HashMap source code implementation analysis

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.