构造方法
- SparseArray():默认的构造函数,最终会调用SparseArray(int size)的重载构造方法
- SparseArray(int size):创建指定大小的keys int数组和values object数组
public SparseArray(int initialCapacity) { if (initialCapacity == 0) { mKeys = EmptyArray.INT; mValues = EmptyArray.OBJECT; } else { mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); mKeys = new int[mValues.length]; } mSize = 0; }
相关API
- put(int key,Object value):添加元素;先通过二分法找到目标key该插入的位置index,如果index位置key与插入的key一致,则直接改对应values位置的值;如果当前位置所对应的value是DELATE对象,则直接更改keys、values所在index的值;如果当前集合被标记有垃圾,需要清理时,会执行集合内部的gc逻辑回收values中的DELATE对象,然后再就添加元素到keys和values中,如果需要扩容,则扩到原来容器的2倍,添加逻辑则是将index至后面所有元素都往后移动一位,然后分别将key、value添加到index位置上
public void put(int key, E value) { // 二分法查找key所在的位置,正数表示key相同,负数表示key不存在 int i = ContainerHelpers.binarySearch(mKeys, mSize, key); // key相同,直接改value if (i >= 0) { mValues[i] = value; } else { i = ~i; // 当前位置的value为被清理状态,则直接改key、value值 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++; } }
- delete(int key):移除指定key对应的value;首先通过二分法找到key所在的索引index,然后将对应index的values位置元素设置为DELETE对象,并将设置为需要清理垃圾状态mGarbage=true,等到下次添加元素时进行清理
public void delete(int key) { int i = ContainerHelpers.binarySearch(mKeys, mSize, key); if (i >= 0) { if (mValues[i] != DELETED) { mValues[i] = DELETED; mGarbage = true; } } }
总结
- SparseArray的数据结构是数组
- SparseArray的优点:keys是有序的;存储元素简单,避免了像HashMap一样,需要对元素进行装箱,不需要在单独封装数据结构
- SparseArray的缺点:由于底层是数组,存在频繁的添加导致效率的降低
- 为何删除元素,不是立即删除?因为SparseArray的数据结构是keys、values2个数组,当每删除一次就移动数组,则大大降低了SparseArray的使用效率,如果等到下次添加时进行清理,当key发生碰撞时,可直接改变当前索引对应的值,就降低了多次移动数组带来的效率影响
- 由于keys是通过二分法来确定key插入的位置,所以就导致了,keys中的元素是有序的
- 由于使用了二分法查找,也大大降低了数组的遍历次数