Java Collection Class Analysis-identyhashmap

Source: Internet
Author: User

First, preface

The previous analysis of HashMap and Linkedhashmap, now we analyze the less common Identityhashmap, from its name can also be seen to represent the only HashMap, carefully analyzed its source code, It is found that the data structure is completely different from the data structure used by HASHMAP because they have no relationship with each other on the inheritance relationship. Below, enter our analysis phase.

Ii. Examples of Identityhashmap 

Import Java.util.map;import Java.util.hashmap;import Java.util.identityhashmap;public class IdentityHashMapTest { Public    static void Main (string[] args) {        map<string, string> hashmaps = new hashmap<string, string> ( );        map<string, string> identitymaps = new identityhashmap<string, string> ();        Hashmaps.put (New String ("AA"), "AA");        Hashmaps.put (New String ("AA"), "BB");                Identitymaps.put (New String ("AA"), "AA");        Identitymaps.put (New String ("AA"), "BB");                System.out.println (hashmaps.size () + ":" + hashmaps);        System.out.println (identitymaps.size () + ":" + Identitymaps);}    }

Operation Result:

1: {AA=BB}
2: {AA=BB, AA=AA}

Description: Identityhashmap is overwritten only if the key is exactly equal (the same reference), and HashMap does not.

Third, IDENTITYHASHMAP data structure

Description: Identityhashmap data is very simple, the underlying is actually an object array, logically need to be seen as a ring array, the solution is to resolve the conflict is: based on the calculation of the hash position, if there are already elements found in the location, then look back until the empty position, Storage, if not, directly to the storage. When the number of elements reaches a certain threshold, the object array is automatically scaled to handle the expansion.

Four, Identityhashmap source analysis

Inheritance relationships for Class 4.1

public class identityhashmap<k,v>    extends abstractmap<k,v>    implements MAP<K,V> Java.io.Serializable, cloneable

Description: Inherits the Abstractmap abstract class, implements the map interface, can serialize the interface, can clone the interface.

Properties of Class 4.2

public class identityhashmap<k,v>    extends abstractmap<k,v>    implements MAP<K,V> Java.io.Serializable, cloneable{    //default capacity size    private static final int default_capacity = +;    Minimum capacity    private static final int minimum_capacity = 4;    Maximum capacity    private static final int maximum_capacity = 1 <<;    Table for storing the actual elements    transient object[] table;    Sizes    int size;    The number of structural modifications to the map    transient int modcount;    The value corresponding to null KEY is    static final object Null_key = new Object ();}

Note: You can see that the bottom layer of the class is using an object array to hold the elements.

constructors for Class 4.3

1. Identityhashmap () type constructor

Public Identityhashmap () {    init (default_capacity);}
Public Identityhashmap () {    init (default_capacity);}

2. Identityhashmap (int) type constructor

Public identityhashmap (int expectedmaxsize) {        if (expectedmaxsize < 0)            throw new IllegalArgumentException (" Expectedmaxsize is negative: "                                               + expectedmaxsize);        Init (Capacity (expectedmaxsize));    }

Public identityhashmap (int expectedmaxsize) {        if (expectedmaxsize < 0)            throw new IllegalArgumentException (" Expectedmaxsize is negative: "                                               + expectedmaxsize);        Init (Capacity (expectedmaxsize));    }

3. Identityhashmap (map<? extends K,? extends v>)-type constructors

Public Identityhashmap (map<? extends K,? extends v> m) {        //Call other constructors this        ((int) ((1 + m.size ()) * 1.1)); C14/>putall (m);    }
Public Identityhashmap (map<? extends K,? extends v> m) {        //Call other constructors this        ((int) ((1 + m.size ()) * 1.1)); 
   putall (m);    }

4.4 Important Function Analysis

1. Capacity function

The value returned by this function is a minimum greater than expectedmaxsize of 2 power    private static int capacity (int expectedmaxsize) {        //Assert Expectedmaxsize >= 0;        Return            (Expectedmaxsize > Maximum_capacity/3)? Maximum_capacity:            (expectedmaxsize <= 2 * minimum_capacity/3)? Minimum_capacity:            integer.highestonebit (expectedmaxsize + (expectedmaxsize << 1));    }
The value returned by this function is a minimum greater than expectedmaxsize of 2 power    private static int capacity (int expectedmaxsize) {        //Assert Expectedmaxsize >= 0;        Return            (Expectedmaxsize > Maximum_capacity/3)? Maximum_capacity:            (expectedmaxsize <= 2 * minimum_capacity/3)? Minimum_capacity:            integer.highestonebit (expectedmaxsize + (expectedmaxsize << 1));    }

Description: The value returned by this function is the smallest and greater than the value of 2 powers of expectedmaxsize.

2. Hash function

hash function, because length is always 2 of the power of N, so & (length-1) equivalent to length modulo    private static int hash (Object x, int length) {        int h = System.identityhashcode (x);        Multiply by-127, and left-shift to use least bits as part of the hash        return ((H << 1)-(H << 8)) & ( length-1);    }
hash function, because length is always 2 of the power of N, so & (length-1) equivalent to length modulo    private static int hash (Object x, int length) {        int h = System.identityhashcode (x);        Multiply by-127, and left-shift to use least bits as part of the hash        return ((H << 1)-(H << 8)) & (L ength-1);    }

Description: The hash function is used for hashing and guarantees that the hash value of the element is even indexed in the array.

3. Get function

Public V get (object key) {        //Guaranteed NULL key will be converted to object (Null_key)        Object k = Masknull (key);        Save table        object[] tab = table;        int len = tab.length;        Get the hash position of the key        int i = hash (k, Len);        To traverse the table, resolve the hash conflict by searching for the idle area while        (true) {            Object item = tab[i] If the conflict occurs;            Determine if equality (address is equal)            if (item = = k)                //address equal, i.e. exactly equal two objects                return (V) Tab[i + 1];            If the element corresponding to the hash position is empty, then an empty            if (item = = NULL) return                null;            Remove a key index            i = Nextkeyindex (i, Len);        }    }
Public V get (object key) {        //Guaranteed NULL key will be converted to object (Null_key)        Object k = Masknull (key);        Save table        object[] tab = table;        int len = tab.length;        Get the hash position of the key        int i = hash (k, Len);        To traverse the table, resolve the hash conflict by searching for the idle area while        (true) {            Object item = tab[i] If the conflict occurs;            Determine if equality (address is equal)            if (item = = k)                //address equal, i.e. exactly equal two objects                return (V) Tab[i + 1];            If the element corresponding to the hash position is empty, then an empty            if (item = = NULL) return                null;            Remove a key index            i = Nextkeyindex (i, Len);        }    }

Description: The function compares whether the key value is identical (the object type is the same reference, and the base type is equal to the content)

4. Nextkeyindex function

Next key index    private static int nextkeyindex (int i, int len) {        //Move backward two units        return (i + 2 < len? i + 2:0 );    }
Next key index    private static int nextkeyindex (int i, int len) {        //Move backward two units        return (i + 2 < len i + 2:0); c3/>}

Description: This function is used to determine when a conflict occurs and a location is removed.

5. Put function

Public V put (K key, V value) {//Guaranteed NULL key will be converted to object (Null_key) Final Object K = Masknull (key); Retryafterresize:for (;;)            {Final object[] tab = table;            final int len = tab.length;            int i = hash (k, Len); for (Object item;                 (item = Tab[i])! = NULL; i = Nextkeyindex (i, Len)) {if (item = = k) {//hash-calculated items are equal to key @SuppressWarnings ("Unch                    Ecked ")//Acquisition value V OldValue = (v) tab[i + 1];                    Deposit value Tab[i + 1] = value;                Returns the old value return oldValue;            }}//size plus 1 final int s = size + 1;            Use optimized form of 3 * s.            Next capacity is Len, 2 * current capacity. If 3 * size is greater than length, the expansion operation will be performed if (S + (s << 1) > Len && resize (len))//After expansionRecalculate the value of the element, find the appropriate location to store continue retryafterresize;            Structural modification plus 1 modcount++;            Store key with value tab[i] = k;            Tab[i + 1] = value;            Update size size = s;        return null; }    }
Public V put (K key, V value) {//Guaranteed NULL key will be converted to object (Null_key) Final Object K = Masknull (key); Retryafterresize:for (;;)            {Final object[] tab = table;            final int len = tab.length;            int i = hash (k, Len); for (Object item;                 (item = Tab[i])! = NULL; i = Nextkeyindex (i, Len)) {if (item = = k) {//hash-calculated items are equal to key @SuppressWarnings ("Unch                    Ecked ")//Acquisition value V OldValue = (v) tab[i + 1];                    Deposit value Tab[i + 1] = value;                Returns the old value return oldValue;            }}//size plus 1 final int s = size + 1;            Use optimized form of 3 * s.            Next capacity is Len, 2 * current capacity. If 3 * size is greater than length, the expansion operation will be performed if (S + (s << 1) > Len && resize (len))//After expansionRecalculate the value of the element, find the appropriate location to store continue retryafterresize;            Structural modification plus 1 modcount++;            Store key with value tab[i] = k;            Tab[i + 1] = value;            Update size size = s;        return null; }    }

Note: If the incoming key already exists in the table (emphasizing that it is the same reference), the new value is substituted for the old value and the old value is returned, and if the number of elements reaches the threshold, then the capacity is expanded, and then the key and value are found in the appropriate location.

6. Resize function

Private Boolean resize (int newcapacity) {//Assert (Newcapacity &-newcapacity) = = newcapacity;//Power of 2        int newlength = newcapacity * 2;        Save the original table object[] oldtable = table;        int oldlength = Oldtable.length;             Whether the old table is twice times the maximum capacity if (Oldlength = = 2 * maximum_capacity) {//can ' t expand any further//before the number of elements is maximum capacity, throws an exception            if (size = = maximum_capacity-1) throw new IllegalStateException ("Capacity exhausted.");        return false;        }//Old table length is greater than new table length, return False if (Oldlength >= newlength) return false;        Generate new Table object[] newtable = new Object[newlength];            Re-hash all elements in the old table into the new table for (int j = 0; J < oldlength; J + = 2) {Object key = Oldtable[j];                if (key = null) {Object value = oldtable[j+1];                OLDTABLE[J] = null;                OLDTABLE[J+1] = null; int i = hash (key, Newlength);                while (newtable[i]! = null) i = Nextkeyindex (i, newlength);                Newtable[i] = key;            Newtable[i + 1] = value;        }}//New table is assigned value to table table = newtable;    return true; }
Private Boolean resize (int newcapacity) {//Assert (Newcapacity &-newcapacity) = = newcapacity;//Power of 2        int newlength = newcapacity * 2;        Save the original table object[] oldtable = table;        int oldlength = Oldtable.length;             Whether the old table is twice times the maximum capacity if (Oldlength = = 2 * maximum_capacity) {//can ' t expand any further//before the number of elements is maximum capacity, throws an exception            if (size = = maximum_capacity-1) throw new IllegalStateException ("Capacity exhausted.");        return false;        }//Old table length is greater than new table length, return False if (Oldlength >= newlength) return false;        Generate new Table object[] newtable = new Object[newlength];            Re-hash all elements in the old table into the new table for (int j = 0; J < oldlength; J + = 2) {Object key = Oldtable[j];                if (key = null) {Object value = oldtable[j+1];                OLDTABLE[J] = null;                OLDTABLE[J+1] = null; int i = hash (key, Newlength);                while (newtable[i]! = null) i = Nextkeyindex (i, newlength);                Newtable[i] = key;            Newtable[i + 1] = value;        }}//New table is assigned value to table table = newtable;    return true; }

Note: When the element in the table reaches the threshold, it expands processing, and the elements in the old table are re-hashed into the new table after the expansion.

7. Remove function

Public V Remove (Object key) {        //Guaranteed NULL key will be converted to object (Null_key)        Object k = Masknull (key);        object[] tab = table;        int len = tab.length;        Computes the hash value        int i = hash (k, Len);        while (true) {            Object item = tab[i];            Find key equal items            if (item = = k) {                modcount++;                size--;                @SuppressWarnings ("unchecked")                    V oldValue = (V) Tab[i + 1];                Tab[i + 1] = null;                Tab[i] = null;                After the deletion, the subsequent processing is required to move the elements that were previously moved by the conflict to the front to                closedeletion (i);                return oldValue;            }            The item is an empty            if (item = = NULL)                return null;            Next item            i = Nextkeyindex (i, Len);}    }
Public V Remove (Object key) {        //Guaranteed NULL key will be converted to object (Null_key)        Object k = Masknull (key);        object[] tab = table;        int len = tab.length;        Computes the hash value        int i = hash (k, Len);        while (true) {            Object item = tab[i];            Find key equal items            if (item = = k) {                modcount++;                size--;                @SuppressWarnings ("unchecked")                    V oldValue = (V) Tab[i + 1];                Tab[i + 1] = null;                Tab[i] = null;                After the deletion, the subsequent processing is required to move the elements that were previously moved by the conflict to the front to                closedeletion (i);                return oldValue;            }            The item is an empty            if (item = = NULL)                return null;            Next item            i = Nextkeyindex (i, Len);}    }

8. Closedeletion function

private void closedeletion (int d) {//Adapted from Knuth section 6.4 algorithm R object[] tab = table;        int len = tab.length; Look for items to swaps into newly vacated slots//starting at index immediately following deletion,//an        D continuing until a null slot is seen, indicating//the end of a run of possibly-colliding keys.        Object item; Move the element that follows the move rule forward to the front for (int i = Nextkeyindex (d, Len);             (item = Tab[i])! = NULL; i = Nextkeyindex (i, Len)) {//The following test triggers if the item at slot I (which//hashes T            o be in slot R) should take the spot vacated by D.  If So, we swaps it in, and then continue with D now at the//newly vacated I.            This process would terminate when we hit//the null slot at the end of this run.            The test is messy because, we are using a circular table.            int r = Hash (item, Len); IF ((I < R && (r <= D | | d <= i)) | | (R <= D && d <= i))                {Tab[d] = Item;                Tab[d + 1] = tab[i + 1];                Tab[i] = null;                Tab[i + 1] = null;            d = i; }        }    }
private void closedeletion (int d) {//Adapted from Knuth section 6.4 algorithm R object[] tab = table;        int len = tab.length; Look for items to swaps into newly vacated slots//starting at index immediately following deletion,//an        D continuing until a null slot is seen, indicating//the end of a run of possibly-colliding keys.        Object item; Move the element that follows the move rule forward to the front for (int i = Nextkeyindex (d, Len);             (item = Tab[i])! = NULL; i = Nextkeyindex (i, Len)) {//The following test triggers if the item at slot I (which//hashes T            o be in slot R) should take the spot vacated by D.  If So, we swaps it in, and then continue with D now at the//newly vacated I.            This process would terminate when we hit//the null slot at the end of this run.            The test is messy because, we are using a circular table.            int r = Hash (item, Len); IF ((I < R && (r <= D | | d <= i)) | | (R <= D && d <= i))                {Tab[d] = Item;                Tab[d + 1] = tab[i + 1];                Tab[i] = null;                Tab[i + 1] = null;            d = i; }        }    }

Description: When an element is deleted, it is closedeletion processed once and the position of the element is reassigned.

Closedeletion before and after the closedeletion.

  

Description: The Assumption: Wherein, ("AA" and "AA") after the hash in the No. 0, ("BB", "BB") after the hash should also be in 0, conflict, move back to the 2nd, ("CC" and "CC") after the hash in the 2nd, there is a conflict, Move back to the 4th item, ("GG", "GG") after the hash in the 2nd item, the conflict, move backward to the 6th item ("DD", "DD") in the 8th item ("EE", "ee") in the 12th item. When deleted ("BB", "BB"), the layout of the elements after processing is shown in the image on the right.

V. Summary

Identityhashmap and HashMap are very different in data structures, and the methods of dealing with hash collisions are not the same. Where Identityhashmap is considered identical only when key is the same reference, and HashMap includes equals equal, that is, the content is the same.

Java Collection Class Analysis-identyhashmap

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.