美文网首页
[原创]ArrayMap源码解析

[原创]ArrayMap源码解析

作者: seekting | 来源:发表于2020-07-17 23:38 被阅读0次

    结构图

    clipboard.png
    public ArrayMap(int capacity, boolean identityHashCode) {
        mIdentityHashCode = identityHashCode;
        
        if (capacity < 0) {
            mHashes = EMPTY_IMMUTABLE_INTS;
            mArray = EmptyArray.OBJECT;
        } else if (capacity == 0) {
            mHashes = EmptyArray.INT;
            mArray = EmptyArray.OBJECT;
        } else {
            allocArrays(capacity);
        }
        mSize = 0;
    }
    

    初始化数组

    private void allocArrays(final int size) {
        mHashes = new int[size];
        "实体数组的长度是hash数组的2倍"
        mArray = new Object[size<<1];
    

    put部分

    @Override
    public V put(K key, V value) {
        final int osize = mSize;
        final int hash;
        int index;
        "identityHashCode只是用来禁用hashcode覆盖"
        hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
        "查看该key在哪个位置或插入哪个位置"
        index = indexOf(key, hash);
    

    关于hashcode禁止覆盖

    public static int identityHashCode(Object x) {
        if (x == null) {
            return 0;
        }
        
        return Object.identityHashCode(x);
    }
    "hashcode的默认实现就是identityHashCode,如果有人覆盖了
    hashcode方法,则用mIdentityHashCode =true可以解决"
    public int hashCode() {
        return identityHashCode(this);
    }
    

    indexof

    int indexOf(Object key, int hash) {
        "通过二分法查找位置"
        int index = binarySearchHashes(mHashes, N, hash);
    

    二分查找

    private static int binarySearchHashes(int[] hashes, int N, int hash) {
        "通过工具类二分法查找"
       return ContainerHelpers.binarySearch(hashes, N, hash);
    }
    static int binarySearch(int[] array, int size, int value) {
        "低位"
        int lo = 0;
        "高位"
        int hi = size - 1;
        while (lo <= hi) {
            "中间位"
            final int mid = (lo + hi) >>> 1;
            "拿中间值"
            final int midVal = array[mid];
            "中间值比要的值小则取右边"
            if (midVal < value) {
                lo = mid + 1;
                "中间值比要的值大取左边"
            } else if (midVal > value) {
                hi = mid - 1;
            } else {
                return mid;  // value found
            }
        }
        "如果没找到,返回他要被插入的位置取反
    取反的目的是告诉调用方每找到,
    但是你下次插入的时候可以用这个位置"
        return ~lo;  // value not present
    }
    
    

    查找后的处理

    int indexOf(Object key, int hash) {
        
        "要么是找到的索引,要么是~插入的索引"
        int index = binarySearchHashes(mHashes, N, hash);
       "不存在就返回索引的取反"
        if (index < 0) {
            return index;
        }
        "存在返回真实值的索引"
        if (key.equals(mArray[index<<1])) {
            return index;
        }
    
        "key的hashcode重复了,向后查【1,2,2,2,2,3】的情况,mid=2先向后查,再向前查,查到返回"
        // 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.
        "此时返回的end是最后一个2的位置后面取反,也是要插入的位置"
        return ~end;
    }
    

    put之二

    @Override
    public V put(K key, V value) {
        "index<0取反就是要插入的位置,否则就是找到了"
        if (index >= 0) {
            index = (index<<1) + 1;
            "替换就行了"
            final V old = (V)mArray[index];
            mArray[index] = value;
            return old;
        }
        "没找到就把要插入的位置算出来"
        index = ~index;
    

    扩容逻辑 1.5倍

    @Override
    public V put(K key, V value) {
        //ignore
        "判断要不要扩容比如上次已经满了"
        if (osize >= mHashes.length) {
            "大于base_size*2的情况就是1。5倍扩容"
            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);
            "检查并发处理异常 调用该方法之前osize=mSize,如果不相等,说明这个方法没走完就有人改了"
            if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
                throw new ConcurrentModificationException();
            }
        
            if (mHashes.length > 0) {
                if (DEBUG) Log.d(TAG, "put: copy 0-" + osize + " to 0");
                "copy"
                System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length);
                System.arraycopy(oarray, 0, mArray, 0, oarray.length);
            }
        
            freeArrays(ohashes, oarray, osize);
        }
    

    数组腾出位置

    @Override
    public V put(K key, V value) {
        "给index后面的数组往后挪一个空格[1,2,3,4,]->[1,2, ,3,4]"
        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);
        }
        
        if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
            if (osize != mSize || index >= mHashes.length) {
                throw new ConcurrentModificationException();
            }
        }
        "index赋植"
        mHashes[index] = hash;
        mArray[index<<1] = key;
        mArray[(index<<1)+1] = value;
        mSize++;
    
    

    get

    @Override
    public V get(Object key) {
        "找到要索引,>=0表示取到,小于0表示没找到"
        final int index = indexOfKey(key);
        return index >= 0 ? (V)mArray[(index<<1)+1] : null;
    }
    @Override
    public int indexOfKey(Object key) {
        return key == null ? indexOfNull()
        "indexof还是二分法找,如果找到了key值相同就返回,key值不同hash一样就向前向后遍历,所以相同hash越多,性能越差"
                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
    }
    

    相关文章

      网友评论

          本文标题:[原创]ArrayMap源码解析

          本文链接:https://www.haomeiwen.com/subject/cseohktx.html