Android Arraymap Source Detailed

Source: Internet
Author: User

respect for the original, reproduced please indicate the source http://blog.csdn.net/abcdef314159

Analysis of the source before the introduction of ARRAYMAP storage structure, ARRAYMAP data storage is different from HashMap and Sparsearray, in the previous "Android Sparsearray source detailed" We talked about the Sparsearray is stored as a pure array, an array is stored in a key value an array is stored value value, today we analyzed the Arraymap and sparsearray a bit similar, he is also in the form of a pure array storage, But the difference is that one of his arrays stores the hash value. The other array stores the key and value, where key and value are paired, the key is stored in the array's even digits, and value is stored on the odd bit of the array, so let's start by looking at one of the construction methods

    public arraymap (int capacity) {        if (capacity = = 0) {            mhashes = containerhelpers.empty_ints;            Marray = containerhelpers.empty_objects;        } else {            allocarrays (capacity);        }        msize = 0;    }
when capacity is not 0, call the Allocarrays method to allocate the array size, before analyzing allocarrays source code, we first look at the Freearrays method,
    private static void Freearrays (final int[] hashes, final object[] array, final int size) {if (Hashes.length = = (base_size*2))                    {synchronized (Arraymap.class) {if (Mtwicebasecachesize < cache_size) {                    Array[0] = Mtwicebasecache;                    ARRAY[1] = hashes;                    for (int i= (size<<1)-1; i>=2; i--) {array[i] = null;                    } Mtwicebasecache = array;                    mtwicebasecachesize++; if (DEBUG) log.d (TAG, "storing 2x cache" + array + "now has" + mtwicebasecachesize + "entr                ies "); }}} and Else if (hashes.length = = base_size) {synchronized (arraymap.class) {i                    F (Mbasecachesize < Cache_size) {array[0] = Mbasecache;                    ARRAY[1] = hashes; for (int i= (size<<1)-1; i>=2; I--) {array[i] = null;                    } Mbasecache = array;                    mbasecachesize++; if (DEBUG) log.d (TAG, "storing 1x Cache" + Array + "now has" + mbasecachesize + "entries")                ; }            }        }    }
The value of base_size is 4, Arraymap for the two cases of Hashes.length 4 and 8 will be cached, the above two cases, the principle is the same, we use one of the following conditions for analysis, the number of caches is not wireless large, when greater than or equal to (cache_ SIZE) is no longer cached, the principle is to let array array of the first place to save the previously cached Mbasecache, the second position to save the current hashes array, the other all empty, let's look at the previous Allocarrays method ,
    private void Allocarrays (final int size) {if (mhashes = = empty_immutable_ints) {throw new Unsuppor        Tedoperationexception ("Arraymap is immutable"); } if (size = = (base_size*2)) {...) {. ...} and ...} else if (size = = Base_size) {synchronized (arraymap.c) {"="}                    Lass) {if (Mbasecache! = null) {final object[] array = Mbasecache;                    Marray = array;                    Mbasecache = (object[]) array[0];                    Mhashes = (int[]) array[1];                    Array[0] = array[1] = null;                    mbasecachesize--; if (DEBUG) log.d (TAG, "retrieving 1x Cache" + Mhashes + "now has" + mbasecachesize + "entr                    ies ");                Return        }}} mhashes = new int[size];    Marray = new object[size<<1]; }
if the allocated size is not 4 or 8, initialize, we see that the bottom two rows of Marray are twice times the size of mhashes, because Marray stores the key and value two values. If the allocated size is 4 or 8, it is judged whether the two cases were cached before, if the cache is taken from the cache, the value of the array will be empty, in the Freearrays method above we know the first position of the array and the second position to save the value, The rest is empty, here array[0] and array[1] are also set to empty, but a little bit of the wonderful thing is that the value of mhashes is guaranteed to stay, either in the Freearrays method or in the Allocarrays method, does not set him as the default value. Through Arraymap source discovery, here the value of mhashes regardless of change does not have much influence basically, because put when the existence is replaced, but in the method of indexof if exist also to continue to compare value, Only key and value will be returned. Let's take a look at the indexof (Object key, int hash) method,
    int indexOf (Object key, int hash) {Final int N = msize;        Important Fast Case:if Nothing was in here and nothing to the look for.        if (N = = 0) {return ~0;        } int index = Containerhelpers.binarysearch (mhashes, N, hash);        If The hash code wasn ' t found, then we had no entry for this key.        if (Index < 0) {return index;        }//If the key at the returned index matches, that's what we want.        if (Key.equals (marray[index<<1])) {return index;        }//Search for a matching key after the index.        int end; for (end = index + 1; end < N && Mhashes[end] = = Hash; end++) {if (Key.equals (marray[end << 1        ]) return end;        }//Search for a matching key before the index. for (int i = index-1; I >= 0 && mhashes[i] = = Hash; i--) {if (Key.equals (marray[i << 1]) r        Eturn i; }//Key not FOund--return negative value indicating where a//new entry for this key should go. We Use the end of the//hash chain to reduce the number of the array entries that would//need to be copied whe        n inserting.    return ~end; }

This method is very simple, is based on the binary search to determine the position of the key in the array, this position is not the index of the array of key, but the subscript one-second, because this array stored not only the key and value, if not found to return a negative number, note that there are two loops, This is because the hash value in the mhashes array is not unique, only the hash value is the same and the key is the same to return to the location, otherwise a negative number is returned. Here's a look at the put (K key, V value) method.

    @Override public V put (K key, V value) {final int hash;        int index;            if (key = = null) {hash = 0;        index = Indexofnull ();            } else {hash = Key.hashcode ();        index = indexOf (key, hash);            }//by looking, if found, replace the original, if (index >= 0) {index = (index<<1) + 1;            Final V old = (v) marray[index];            Marray[index] = value;        return old; }//in the previous "Android Sparsearray source details," said, according to the dichotomy method, if not found will return a negative number, here to take the inverse index = ~index;//If full of the expansion if (msize >= MH Ashes.length) {//Size of expansion, trinocular operator final int n = msize >= (base_size*2)? (Msize+ (Msize>>1)): (Msize >= base_size?)            (base_size*2): base_size);            if (DEBUG) log.d (TAG, "put:grow from" + Mhashes.length + "to" + N);            Final int[] ohashes = mhashes;          Final object[] Oarray = marray;//expansion allocarrays (n);//If the original data is copied to the enlarged array  if (Mhashes.length > 0) {if (DEBUG) log.d (TAG, "Put:copy 0-" + msize + "to 0");                System.arraycopy (ohashes, 0, mhashes, 0, ohashes.length);            System.arraycopy (Oarray, 0, Marray, 0, oarray.length);        } freearrays (Ohashes, Oarray, msize); }//based on the dichotomy above, if index is less than msize, the new data is inserted between the array index position, insert before inserting need to put the rear shift if (Index < msize) {if (DEBUG) log.d            (TAG, "put:move" + Index + "-" + (Msize-index) + "to" + (index+1));            System.arraycopy (mhashes, index, mhashes, index + 1, msize-index);        System.arraycopy (Marray, index << 1, Marray, (index + 1) << 1, (Msize-index) << 1);        }//data Save, mhashes only hash value, Marray that is to save the key value and save value, mhashes[index] = hash;        MARRAY[INDEX&LT;&LT;1] = key;        marray[(index<<1) +1] = value;        msize++;    return null; }
There is also the clear () method and the Erase () method, which is clear () clears all the data and frees up space, erase () empties the data but does not free up space, and erase () clears Marray data, mhashes data is not emptied, This is the above mentioned mhashes even if not emptied will not have an impact, less code is not seen. Look at a method similar to put append (K key, V value)

    /** * Special fast path for appending items to the end of the array without validation.     * The array must already is large enough to contain the item.        * @hide */public void append (K key, V value) {int index = msize; Final int hash = key = = null?        0:key.hashcode ();        if (index >= mhashes.length) {throw new IllegalStateException ("Array is full"); } if (Index > 0 && mhashes[index-1] > hash) {runtimeexception e = new RuntimeException ("H            Ere ");            E.fillinstacktrace ();  LOG.W (TAG, "New hash" + hash + "is before end of array hash" + mhashes[index-1] +            "at index" + Index + "key" + key, E);            Put (key, value);        Return        } msize = index+1;        Mhashes[index] = hash;        Index <<= 1;        Marray[index] = key;    MARRAY[INDEX+1] = value; }
We look at the note that this method is hidden, not open, because this method is not stable, if the call may be problematic, look at the above comment, meaning that this method of storing data is not verified, because at the time of the last storage, is directly stored in, this will have a problem, If you have previously stored the same key and value, and then call this method, it is likely to be deposited again, there may be two keys and value exactly the same, I personally think if the above if (Index > 0 && mhashes[index-1) > Hash) Change to if (Index > 0 && mhashes[index-1] >= hash) should be OK, because if there is the same call put method to replace the original, do not understand why he wrote, Here's another way to see Validate ()

    /** * The use of the {@link #append} function can result in invalid array maps, in particular * An array map W  Here the same key appears multiple times.  This function verifies the array map is valid, throwing illegalargumentexception if a problem is found. The * main use for this method is validating a array map after unpacking from a IPC, to * Protect against Malici     OUs callers.        * @hide */public void Validate () {final int N = msize;            if (N <= 1) {//There can ' t be dups.        Return        } int basehash = mhashes[0];        int Basei = 0;            for (int i=1; i<n; i++) {int hash = mhashes[i];                if (hash! = Basehash) {Basehash = hash;                Basei = i;            Continue  }//We are in a run of entries with the same hash code.            Go backwards through//the array to see if any keys is the same. Final OBJECT cur = marray[i<<1];                for (int j=i-1; j>=basei; j--) {final Object prev = marray[j<<1];                if (cur = = prev) {throw new IllegalArgumentException ("Duplicate Key in Arraymap:" + cur); } if (cur! = null && prev! = null && cur.equals (prev)) {throw new                IllegalArgumentException ("Duplicate Key in Arraymap:" + cur); }            }        }    }
See the above comment is also hidden, there may be a number of the same key when stored, this method is used to verify, this method is very well understood, because we store the data in accordance with the dichotomy to find and then store, If the key value is the same, then the storage must be next to each other, verify here, the value of the data next to the same key is compared, if the value is the same, it is already present, the exception is reported. Let's take a look at the last method
    Public V removeAt (int index) {final Object old = marray[(index << 1) + 1];//if less than or equal to 1 empty if (msiz            E <= 1) {//Now empty.            if (DEBUG) log.d (TAG, "remove:shrink from" + mhashes.length + "to 0");            Freearrays (Mhashes, Marray, msize);            Mhashes = Emptyarray.int;            Marray = Emptyarray.object;        msize = 0; } else {//If the array is larger, but uses less, it will reallocate the space if (Mhashes.length > (base_size*2) && Msize < Mhashes.length  /3) {//shrunk enough to reduce size of arrays. We don ' t allow it to//shrink smaller than (base_size*2) to avoid flapping between//That And base_size.//recalculates the space, when greater than 8 will increase 1.5 times times the final int n = msize > (base_size*2)?                (Msize + (msize>>1)): (base_size*2);                if (DEBUG) log.d (TAG, "remove:shrink from" + Mhashes.length + "to" + N);                Final int[] ohashes = mhashes; FinAl object[] Oarray = marray;//reallocate space allocarrays (n);                msize--;  if (Index > 0) {//If the deleted position is greater than 0, copy the first half to the new array if (DEBUG) log.d (TAG, "remove:copy from 0-" + index + "to                    0 ");                    System.arraycopy (ohashes, 0, mhashes, 0, index);                System.arraycopy (Oarray, 0, Marray, 0, index << 1); if (Index < msize) {//If the deleted position is less than msize, copy the data from the index position to the new array if (DEBUG) log.d (TAG, "R                    Emove:copy from "+ (index+1) +"-"+ Msize +" to "+ index);                    System.arraycopy (ohashes, index + 1, mhashes, index, msize-index); System.arraycopy (Oarray, (index + 1) << 1, Marray, index << 1, (Msize-index) <                < 1);                }} else {msize--; if (Index < msize) {//Ibid. if (DEBUG) log.d (TAG, "Remove: Move "+ (index+1) +"-"+ Msize +" to "+ index);                    System.arraycopy (mhashes, index + 1, mhashes, index, msize-index); System.arraycopy (Marray, (index + 1) << 1, Marray, index << 1, (Msize-index) <                < 1); }//the removed position is empty, the above why is not empty, because the above data is copied to a new array, and the deletion is not//copy, here to empty is because there is no expansion of the array, or in the original array operation, so must empty Marray[msize <                < 1] = null;            marray[(msize << 1) + 1] = null;    }} return (V) old; }

The rest of the methods are relatively simple, and this is not a single analysis.



Android Arraymap Source Detailed

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.