SparseArray是android里为<Interger,Object> 这样的Hashmap而专门写的类,目的是提高效率,其核心是折半查找函数(binarySearch)。
满足下面两个条件我们可以使用SparseArray代替HashMap:
1. 数据量不大,最好在千级以内
2. key必须为int类型或者long,这中情况下的HashMap可以用SparseArray或LongSparseArray代替
参考:
https://liuzhichao.com/p/832.html
满足下面两个条件我们可以使用SparseArray代替HashMap:
1. 数据量不大,最好在千级以内
2. key必须为int类型或者long,这中情况下的HashMap可以用SparseArray或LongSparseArray代替
3、如果key类型为其它的类型,则使用ArrayMap
之后需要分析一下ArrayMap
参考:
https://liuzhichao.com/p/832.html
http://blog.csdn.net/u010687392/article/details/47809295
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false; //是否可以回收,即清理mValues中标记为DELETED的值的元素
private int[] mKeys; //保存键的数组
private Object[] mValues; //保存值的数组
private int mSize; //当前已经保存的数据个数
/**
* Creates a new SparseArray containing no mappings.
*/
public SparseArray() {
this(10);
}
//仅用两个数组来保存对象,不需要额外的存储空间
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;
}
//通过二分查找法,在mKeys数组中查询key的位置,然后返回mValues数组中对应位置的值,找不到则返回默认值
public E get(int key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i < 0 || mValues[i] == DELETED) {
return valueIfKeyNotFound;
} else {
return (E) mValues[i];
}
}
//通过二分查找法,在mKeys数组中查询key的位置,然后将mValues数组中对应位置的值设置为DELETED
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
mGarbage = true;
}
}
}
//遍历mValues,将标记了DELETED的位置的右侧的值向左侧挪动,并重置mSize
private void gc() {
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
Object val = values[i];
if (val != DELETED) {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;
}
//根据key的大小,计算它在mKeys中应该的位置,在该位置中插入key,和value
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else { //负值表示它应该插入到一个位置中,可能是已有的位置之间,也可能是最后
i = ~i;
//如果要插入到位置之间,但正好右侧的值为DELETED,就不需要插入了而是直接覆盖
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
//如果之前删除过某个value还没有进行垃圾回收,并且mKeys的值已经满了,即将需要扩容
//则进行一次垃圾回收,缩小mKeys和mValues实际的元素数量mSize
if (mGarbage && mSize >= mKeys.length) {
gc();
// Search again because indices may have changed.
//一定还是找不到合适的位置而需要插入新对象
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
//在位置i插入新元素
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
//返回gc后真实的元素数量
public int size() {
if (mGarbage) {
gc();
}
return mSize;
}
public int keyAt(int index) {
if (mGarbage) {
gc();
}
return mKeys[index];
}
public E valueAt(int index) {
if (mGarbage) {
gc();
}
return (E) mValues[index];
}
public void setValueAt(int index, E value) {
if (mGarbage) {
gc();
}
mValues[index] = value;
}
//通过二分查找,返回key所在的位置,可能是负值表示目前没有存储过key但是它应该的位置是多少
public int indexOfKey(int key) {
if (mGarbage) {
gc();
}
return ContainerHelpers.binarySearch(mKeys, mSize, key);
}
//便利数组返回value所在位置,-1表示未找到
public int indexOfValue(E value) {
if (mGarbage) {
gc();
}
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
public void clear() {
int n = mSize;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
values[i] = null;
}
mSize = 0;
mGarbage = false;
}
public void append(int key, E value) {
//key值在已有的key值数组的范围内,则调用put插入
if (mSize != 0 && key <= mKeys[mSize - 1]) {
put(key, value);
return;
}
//key值在范围外,先gc,然后直接追加在数组最后
if (mGarbage && mSize >= mKeys.length) {
gc();
}
mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
mValues = GrowingArrayUtils.append(mValues, mSize, value);
mSize++;
}
}
public static <T> T[] insert(T[] array, int currentSize, int index, T element) {
assert currentSize <= array.length;
//如果数组容量大于其中已经占用的元素数量,则将element插入到index位置,原来index以及之后的元素整体向后移动
if (currentSize + 1 <= array.length) {
System.arraycopy(array, index, array, index + 1, currentSize - index);
array[index] = element;
return array;
}
//此时currentSize和array.length相等,array扩容成newArray,复制并插入element
T[] newArray = ArrayUtils.newUnpaddedArray((Class<T>)array.getClass().getComponentType(),
growSize(currentSize));
System.arraycopy(array, 0, newArray, 0, index);
newArray[index] = element;
System.arraycopy(array, index, newArray, index + 1, array.length - index);
return newArray;
}
public static <T> T[] append(T[] array, int currentSize, T element) {
assert currentSize <= array.length;
//数组已满,需要扩容
if (currentSize + 1 > array.length) {
@SuppressWarnings("unchecked")
T[] newArray = ArrayUtils.newUnpaddedArray(
(Class<T>) array.getClass().getComponentType(), growSize(currentSize));
System.arraycopy(array, 0, newArray, 0, currentSize);
array = newArray;
}
//放在数组最后一个实际元素的后面
array[currentSize] = element;
return array;
}
//找到则返回所在的位置,否则返回它应该在的位置并取反
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
}