• Android ArrayMap源码解析


    数据结构:

        int[] mHashes;
        Object[] mArray;
    
    • 1
    • 2

    为两个数组实现,mHashes 负责记录Key的hash,key的hash所在的位置index,在mArray对应的位置 index2 为Key index2 + 1 为value
    mHashes 里面的元素是经过排序的 支持二分查找

    增删改查

    Put操作:

        public V put(K key, V value) {
            final int osize = mSize;
            final int hash;
            int index;
            if (key == null) {
                hash = 0;
                index = indexOfNull();
            } else {
                hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
                index = indexOf(key, hash);
            }
    		//已经存在相同的key
            if (index >= 0) {
                index = (index<<1) + 1;
                final V old = (V)mArray[index];
                mArray[index] = value;
                return old;
            }
    		//不存在key ~index 就会返回key应该所在的位置
            index = ~index;
            if (osize >= mHashes.length) {
                final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
                        : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
    
                final int[] ohashes = mHashes;
                final Object[] oarray = mArray;
                allocArrays(n);
    
                if (mHashes.length > 0) {
                    if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
                    System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
                    System.arraycopy(oarray, 0, mArray, 0, oarray.length);
                }
    
                freeArrays(ohashes, oarray, osize);
            }
    
            if (index < osize) {
                if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (osize-index)
                        + " to " + (index+1));
                System.arraycopy(mHashes, index, mHashes, index + 1, osize - index);
                System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1);
            }
    
            mHashes[index] = hash;
            mArray[index<<1] = key;
            mArray[(index<<1)+1] = value;
            mSize++;
            return null;
        }
    
        int indexOf(Object key, int hash) {
            final int N = mSize;
    
            // Important fast case: if nothing is in here, nothing to look for.
            if (N == 0) {
                return ~0;
            }
    		//二分查找Key的位置
            int index = binarySearchHashes(mHashes, N, hash);
    		//<0  表示不存在  同时~index 会表示Key应该所在的位置
            // If the hash code wasn't found, then we have no entry for this key.
            if (index < 0) {
                return index;
            }
    
    		//hasCode相同的情况呢? 会对key进行比较equals 直到找到对应的Key
            // 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])) return 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 array entries that will
            // need to be copied when inserting.
            return ~end;
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90

    Key对应的Hash 放入数组的时候,会进行排序
    这样对于hasCode 就可以进行二分查找

    get比较简单 直接返回mArray的value值即可

        public V get(Object key) {
            final int index = indexOfKey(key);
            return index >= 0 ? (V)mArray[(index<<1)+1] : null;
        }
    
    • 1
    • 2
    • 3
    • 4

    删除
    正常删除,当数组满足回收条件的时候 回收数组 下一次使用

        public V remove(Object key) {
            final int index = indexOfKey(key);
            if (index >= 0) {
                return removeAt(index);
            }
    
            return null;
        }
        public V removeAt(int index) {
    
            final Object old = mArray[(index << 1) + 1];
            final int osize = mSize;
            final int nsize;
            if (osize <= 1) {
                // Now empty.
                if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to 0");
                final int[] ohashes = mHashes;
                final Object[] oarray = mArray;
                mHashes = EmptyArray.INT;
                mArray = EmptyArray.OBJECT;
                freeArrays(ohashes, oarray, osize);
                nsize = 0;
            } else {
                nsize = osize - 1;
                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.
                    final int n = osize > (BASE_SIZE*2) ? (osize + (osize>>1)) : (BASE_SIZE*2);
    
                    if (DEBUG) Log.d(TAG, "remove: shrink from " + mHashes.length + " to " + n);
    
                    final int[] ohashes = mHashes;
                    final Object[] oarray = mArray;
                    allocArrays(n);
    
                    if (index > 0) {
                        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 < nsize) {
                        if (DEBUG) Log.d(TAG, "remove: copy from " + (index+1) + "-" + nsize
                                + " to " + index);
                        System.arraycopy(ohashes, index + 1, mHashes, index, nsize - index);
                        System.arraycopy(oarray, (index + 1) << 1, mArray, index << 1,
                                (nsize - index) << 1);
                    }
                } else {
                    if (index < nsize) {
                        if (DEBUG) Log.d(TAG, "remove: move " + (index+1) + "-" + nsize
                                + " to " + index);
                        System.arraycopy(mHashes, index + 1, mHashes, index, nsize - index);
                        System.arraycopy(mArray, (index + 1) << 1, mArray, index << 1,
                                (nsize - index) << 1);
                    }
                    mArray[nsize << 1] = null;
                    mArray[(nsize << 1) + 1] = null;
                }
            }
            if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
                throw new ConcurrentModificationException();
            }
            mSize = nsize;
            return (V)old;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    为什么省内存?

    1.初始化内存较小
    ArrayMap 默认为4 BASE_SIZE = 4
    HashMap默认为16 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4
    2.增长策略不同
    HashMap每次都是翻倍
    newCap = oldCap << 1
    ArrayMap 为:4 -> 8 -> 1.5倍

                final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
                        : (osize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE);
    
    • 1
    • 2

    3.ArrayMap 不需要创建Entry对象 因为全是数组保存的Key Value
    4.ArrayMap使用了缓存池
    当创建的数组不用的时候 会进行回收

    	//长度为4的数组静态缓存池
        static Object[] mBaseCache;
        static int mBaseCacheSize;
    	//长度为8的数组静态缓存池
        static Object[] mTwiceBaseCache;
        static int mTwiceBaseCacheSize;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    Node.js及其http模块简介
    音频基础知识和音频指标
    goland报错:“package command-line-arguments is not a main package”解决方案
    40.CSS输入字段文本和渐变边框动画效果
    【Rust】快速教程——冻结&表达式
    MySQL 高级知识之使用 mysqldump 备份和恢复
    数据结构试题(一)
    docker的基本使用
    合并两个有序数组(美团面试)
    PyCharm及Python3.10.5安装配置教程
  • 原文地址:https://blog.csdn.net/u013270444/article/details/126933676