Google为什么建议使用 SpareArray代替HashMap

xiaoxiao2021-02-28  31

         在做android开发很多年的时间里面,很多人都知道要使用 SpareArray,但是并不知道为什么。今天就来聊一聊SpareArray的实现源码,讲解下当前SpareArray的实现原理。

一、首先看下SpareArray的构造函数:

    public SparseArray() {        this(10);    }

    public SparseArray(int initialCapacity) {        if (initialCapacity == 0) {            mKeys = ContainerHelpers.EMPTY_INTS;            mValues = ContainerHelpers.EMPTY_OBJECTS;        } else {            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);            mKeys = new int[initialCapacity];            mValues = new Object[initialCapacity];        }        mSize = 0;

    }

 默认是分配一个数组长度为10,分别分配一个保存int类型的key,一个保存Object类型的值。

二、增加相应的数据 它有两个方法可以添加键值对: public   void  put( int  key, E value)   public   void  append( int  key, E value)   

    public void put(int key, E value) {        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);        if (i >= 0) {            mValues[i] = value;        } else {            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);            }            if (mSize >= mKeys.length) {                int n = ArrayUtils.idealIntArraySize(mSize + 1);                int[] nkeys = new int[n];                Object[] nvalues = new Object[n];                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);                mKeys = nkeys;                mValues = nvalues;            }            if (mSize - i != 0) {                // Log.e("SparseArray", "move " + (mSize - i));                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);            }            mKeys[i] = key;            mValues[i] = value;            mSize++;        }

    }

     在上面添加数据的代码中发现,里面使用了一个非常重要的方法,就是二分查找法,来查找当前key的位置,然后,在适当的位置把当前值插入进去,因此,SparseArray添加的数组的内容一定是有序的。并且,它存储的数值都是按键值从小到大的顺序排列好的。其实append方法的实现方式和put的实现方式类似,这里不再详细讲解。

三、查 它有两个方法可以取值: public E get(int key)  public E get(int key, E valueIfKeyNotFound)   最后一个从传参的变量名就能看出,传入的是找不到的时候返回的值 查看第几个位置的键: public   int  keyAt( int  index)   查看第几个位置的值: public  E valueAt( int  index)   查看键所在位置,由于采用二分法查找键的位置,所以 没有的话返回小于0的数值,而不是返回-1 ,这点要注意,返回的负数其实是表示它在哪个位置就找不到了,如果你存了5个,查找的键大于5个值的话,返回就是-6:      public   int  indexOfKey( int  key)   查看值所在位置,没有的话返回-1: public   int  indexOfValue(E value)   四、删 它有两个方法: public void delete(int key)  public void remove(int key)   但其实,delete和remove的效果是一样的,remove方法中调用了delete方法,remove源码: public   void  remove( int  key) {           delete(key);   }  

还有一个clear方法,就是全部清除当前的所有数据。

通过上面的简单分析,基本可以知道,SparseArray使用的是纯数组的方式来实现的,不管是key,还是value都是一个数组。

而HashMap使用的是散列表(数组+链表)的方式实现的,查询数据的计算方式也比数组要复杂。关于HashMap的实现原理,将在下一个章节中讲解。另外,SparseArray实现了Cloneable接口,还可以调用clone方法。

对比当前的性能,总结如下:

1.SpareseArray 也是通过键值对存储数据,只是key为整形int , 类似于key = Interger 的HashMap,但是SpareseArray 的key 为 int 非 Interger ,更省空间。 2. SpareArray 意为稀松数组,其结构类似于数组结构,依次排开;HashMap是散列列表,根据hash值来存储;因此SpareArray 会比 HashMap节省很多空间。 3.从查找速度 和 插入效率来看,如果是正序插入( 0 ->size插入),SpareArray 的插入效率会高于 HashMap。 4.如果是逆序插入(size -> 0)的顺序插入,则SpareArray 的插入效率表现是最差的,会低于HashMap。 5. SpareArray 在逆序插入效率很低,是因为 每次插入 SpareArray 都会采用二分查找来定位。 6. 从查找速度来来考虑,HashMap的查找速度 会 高于 SparseArray。 于是, 通过以上分析,SpareArray 相对于 HashMap的最大优势在内存空间。 因此谷歌推荐使用 SpareArray 代替 HashMap 。
转载请注明原文地址: https://www.6miu.com/read-2614678.html

最新回复(0)