美文网首页
[原创]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源码解析

    结构图 初始化数组 put部分 关于hashcode禁止覆盖 indexof 二分查找 查找后的处理 put之二 ...

  • ArrayMap源码解析

    ArrayMap 使用2个数组。它的对象实例内部有用来存储对象的 Object[] mArray 和 存储哈希值的...

  • ArrayMap源码解析

    上篇文章是SparseArray源码解析,这篇文章分析下ArrayMap的源码。 在移动设备端内存资源很珍贵,Ha...

  • ArrayMap解析

    注:来自于Android中ArrayMap的解析问题:1、ArrayMap采用的数据结构是?2、ArrayMap默...

  • 面试必备:ArrayMap源码解析

    本文出自:【张旭童的简书】 (http://www.jianshu.com/users/8e91ff99b072/...

  • 安卓-ArrayMap源码解析

    1 概述在上文中,我们已经聊过了HashMap和LinkedHashMap.所以如果没看过上文,请先阅读HashM...

  • 源码的魅力 - ArrayMap的工作原理

    ArrayMap的工作原理(Android 7.1源码) 其他相关文章 源码的魅力 - ArrayDeque 的工...

  • SparseArray原理分析

    系列文章地址:Android容器类-ArraySet原理解析(一)Android容器类-ArrayMap原理解析(...

  • SparseIntArray原理分析

    系列文章地址:Android容器类-ArraySet原理解析(一)Android容器类-ArrayMap原理解析(...

  • ArrayMap源码分析

    ArrayMap是Android提供的一种替换HashMap的数据结构,官方对它的介绍说ArrayMap是一种更有...

网友评论

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

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