Implementation of HashMap source code in a Java Collection

Source: Internet
Author: User

Implementation of HashMap source code in a Java Collection
1. Through the above article, we know that the underlying layer of HashSet is implemented by Map. What is Map? How is it implemented at the underlying layer? Next, let's 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"). Each key is mapped to a value. Map. Entry is its internal class, which describes the key/value pairs in Map. It must be noted that Map allows null keys and null values. Its implementation mainly includes HashMap and sortedMap. SortedMap extends Map to keep keys sorted in ascending order. Next we will briefly analyze the implementation of HashMap. The following is an example of an 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 stub Map <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"); // boolean System. out. println (map. containsValue ("A"); // boolean System. 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> en Try = map. entrySet (); map. clear () ;}} 2. the inheritance structure HashMap directly inherits the AbstractMap class and implements the Map <K, V>, Cloneable, and Serializable interfaces. In addition to these inheritance and implementations, it also has some important attribute values. Take a simple look: DEFAULT_INITIAL_CAPACITY: default initial capacity (16); MAXIMUM_CAPACITY: Maximum capacity allowed (1 <30); DEFAULT_LOAD_FACTOR: Default loading Factor (0.75 ); entry [] table: stores specific values. Transient int size: record the Map size. Final float loadFactor: load factor. In addition to the Entry type, what does this mean. Originally, this is the class for maintaining the Map key value, which is used to store the specific Map value. Let's take a look at its specific 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 = valu E; value = newValue; return oldValue;} 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 = null? 0: value. hashCode ();} public final String toString () {return getKey () + "=" + getValue ();} /*** This method is invoked whenever the value in an 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 entry is * removed from the table. */void recordRemoval (HashMap <K, V> M) {}} Entry <K, V> implements the internal interface Map in the Map interface. entry <K, V>, key, and value are used to store key values respectively. Entry <K, V> next also points to the next node pointer, it indicates that the storage space of Map is not continuous and can be dispersed. The Hash attribute indicates that the key position is calculated based on the Hash value. Note that this occurs as an internal class of HashMap. In addition, there are internal classes such as KeySet, Values, EntrySet, ValueIterator, KeyIterator, and EntryIterator. However, you can see their specific functions through the class name. 3. source code parsing a: constructor public HashMap (int initialCapacity, float loadFactor) {if (initialCapacity <0) throw new IllegalArgumentException ("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_FACT OR); table = new Entry [DEFAULT_INITIAL_CAPACITY]; init ();} public HashMap (Map <? 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 <? Extends 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. the getValue () ;}} constructor only needs to describe the first one. Others are to pass some default parameter values and then call the first constructor to perform specific operations. Focus on the first constructor. It first checks whether the incoming capacity is valid and whether the load factor is valid. If the maximum capacity operation value needs to be reset, but if the input value is negative, an exception is thrown. Then, the critical value is obtained based on the product of capacity and loading Factor and assigned to the attribute threshold. Then, the storage space is allocated through table = new Entry [capacity] to complete the construction process. The Init () method is empty and does not know what to do. 2. hash (int h) static int hash (int h) {// This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor ). h ^ = (h >>>> 20) ^ (h >>>> 12); return h ^ (h >>>> 7) ^ (h >>> 4 );} the key location is determined based on the Hash value. If the input value is null, the returned hash value is 0, and the index value is 0. 3. size (), isEmpty () public int size () {return size;}/*** Re Turns <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 directly returns the value of the attribute value size. If the size is 0, the value is null. Otherwise, the value is not empty. 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;} return the corresponding value based on the key. First, judge whether the key is null. If it is null, call getForNullKey () to return only one value corresponding to the null key. In fact, the first value of Map is returned. Because the hash value corresponding to null is 0, the storage location is the first one. Then call the hash () method to return the unique corresponding hash value, and then traverse the Map again. If the Hash value is found to be equal, its value is directly returned, if no corresponding value is found, null is returned. 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;} first obtain the value to determine whether a value exists, if the obtained value is not null, the object exists. The getKey () method is used to obtain the key. First, obtain the Hash value, and then traverse the Entry array. If the key is the same, the return value is null. 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 objects to the Map. First, we determine whether the Input Key is null. If it is null, we call putF directly. The orNullKey (value) method maps the null key to the upper value. If it is not empty, first obtain the Hash value corresponding to K, and then traverse the loop Map. If the value already exists, the overwrite value is updated and the old value is returned, otherwise, addEntry (hash, key, value, I) is called to insert a new value. It's easy to insert and simply add a New Entry object and determine the position of the array to specify the value. 4. Other HashMap implementations are not synchronized, which means it is not thread-safe. Its key and value can all be null. In addition, the ing in HashMap is not sequential. The HashMap instance has two parameters that affect its performance: "initial capacity" and "loading factor ". Capacity is the amount of data in the hash table. The initial capacity is only the size of the hash table at creation. 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, You need to rehash the hash table (that is, rebuild the internal data structure ), in this way, the hash table will have approximately two times the number.

Related Article

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.