SparseArray和ArrayMap

本文深入探讨了Android中两种优化过的数据结构——SparseArray和ArrayMap。SparseArray针对int key优化,利用二分查找提高效率,适合存储整数键值对。ArrayMap则支持Object key,其内部使用hash值定位,同样采用二分查找,提供了一种在性能和内存使用上的平衡。两者都是为了在Android环境中提升性能,减少对象创建和内存消耗。
摘要由CSDN通过智能技术生成

Java数据结构够多了吧,为了不同角度的性能又提出了SparseArray等系列。直译就是稀疏数组。实际好多同Map还有HashMap作比较实际有啥好比较的。HashMap的key可以除开基本类型的任意类型,但是SparseArray实际的key值是int,跟ArrayList这种数组才有可比性。ArrayList就是简单利用数组来做的。
SparseArray 也是利用数组,不过key是一个数组,value是一个数组。为啥要这么做,为啥体现稀疏性,来看看put和get方法便知。

public void put(int key, E value) {
//在mkey数组查找是否有此key
    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
//命中。 
    if (i >= 0) {
        //直接修改了。
        mValues[i] = value;
    } else {
        //binarySearch 会返回来一个~i,这个时候折回去。
        i = ~i;

        if (i < mSize && mValues[i] == DELETED) {
            mKeys[i] = key;
            mValues[i] = value;
            return;
        }

        if (mGarbage && mSize >= mKeys.length) {
            gc();

            // Search again because indices may have changed.
            i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
        }
        //直接插入数据,同时会动态扩容。
        mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
        mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
        mSize++;
    }
}

现在看看get方法。

public E get(int key, E valueIfKeyNotFound) {
//也是先二分查找相关key。如果找到就直接取值,找不到就null。
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i < 0 || mValues[i] == DELETED) {
            return valueIfKeyNotFound;
        } else {
            return (E) mValues[i];
        }
    }

可以看到学习这个关键在于这个key的数组是个升序排列,然后通过二分查找。这样确实比较快,对于android性能相较于HashMap有提升这就是SparseArray存在的意义,注意安卓对性能提升非常关注。
再看看ArrayMap 对性能提升有什么影响。看下构造方法。

public ArrayMap(int capacity, boolean identityHashCode) {
      mIdentityHashCode = identityHashCode;

      // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
      // instance instead of the usual EmptyArray.INT. The reference
      // is checked later to see if the array is allowed to grow.
      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;
  }
  mHashed就是key的hash值,mArray就是value值。

为啥要多出来一个mHashes呢,可以看下这个put和get方法。

  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();
            //查询key对于的index。如果不存在会是一个经过二分查找不存在的index,取反。
            index = indexOf(key, hash);
        }
        //存在,那么需要存储的位置2*index+1.
        if (index >= 0) {
            index = (index<<1) + 1;
            final V old = (V)mArray[index];
            mArray[index] = value;
            return old;
        }
        //不存在。
        index = ~index;
        if (osize >= mHashes.length) {
            final int n = osize >= (BASE_SIZE*2) ? (osize+(osize>>1))
                    : (osize >= 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;
            allocArrays(n);

            if (CONCURRENT_MODIFICATION_EXCEPTIONS && osize != mSize) {
                throw new ConcurrentModificationException();
            }

            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);
        }

        if (CONCURRENT_MODIFICATION_EXCEPTIONS) {
            if (osize != mSize || index >= mHashes.length) {
                throw new ConcurrentModificationException();
            }
        }
        //存值。
        mHashes[index] = hash;
        mArray[index<<1] = key;
        mArray[(index<<1)+1] = value;
        mSize++;
        return null;
    }

可以看到mArray的排列,是key和value间隔排列的。然后还有个hash数组。这样首先通过hash数组确立具体的index值。然后通过index值去找到相应的value。这个其实有点类似SparseArray的加强版,因为它能够key值为object。现在总结下类似key,vaue结构的数据结构。一般有两种方法,一种是Hash式存储,这种一般是解决key值为Object的情况。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值