SparseArray类似于map形式的集合对象,其实是一个key为int[]数组,value是object[]数组的形式,支持K,V 结构的mapping数据对象。初始化容量为10.且keys的数组会自动升序排列,方便通过二分查找快速定位到数据。
效率高,适合少量数据。
以下的这几个对象和SparseArray的机制一样,所以不做深入研究。
SparseIntArray : key只能int 类型,value 是int类型。
SparseLongArray: key只能int 类型,value 是Long类型。
SparseBooleanArray : key只能int 类型,value 是Boolean类型。
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();
private boolean mGarbage = false;
@UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)
private int[] mKeys;
@UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, E)
private Object[] mValues;
@UnsupportedAppUsage(maxTargetSdk = 28) // Use size()
private int mSize;
/**
* Creates a new SparseArray containing no mappings.
*/
public SparseArray() {
this(10);
}
添加数据
binarySearch先通过二分查找,查询当前数据是否已经存在该key,如果有就返回它的下标,且把数据覆盖旧数据,如果没有就返回反值,这个地方一定要举个列子,假如数组为 int [] arr = {100,200,300,400,500}; size 是5,我要插入一个555,这个555肯定不存在数组里,它就是返回-6,回到put方法里, i = ~i; 取反值就是又是5了,5就相当于数组的下一个值,就是给下一位赋值,这样就基于以前的数据,进行数组的添加操作。
/**
* Adds a mapping from the specified key to the specified value,
* replacing the previous mapping from the specified key if there
* was one.
*/
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
//没有找到下标,最终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++;
}
}
// 输入key值,通过二分查找,查询它的下标。注意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
}
GrowingArrayUtils通过名字就可以看到,它是管理数组增长的工具类。同时它还维护了数组的顺序,升序排列。
/**
* Inserts an element into the array at the specified index, growing the array if there is no
* more room.
*
* @param array The array to which to append the element. Must NOT be null.
* @param currentSize The number of elements in the array. Must be less than or equal to
* array.length.
* @param element The element to insert.
* @return the array to which the element was appended. This may be different than the given
* array.
*/
public static <T> T[] insert(T[] array, int currentSize, int index, T element) {
assert currentSize <= array.length;
if (currentSize + 1 <= array.length) {
System.arraycopy(array, index, array, index + 1, currentSize - index);
array[index] = element;
return array;
}
@SuppressWarnings("unchecked")
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;
}
获取方法;
get方法就很简答,通过key获取下标位置,根据下标位置直接从数组取出数组,当然如果找不到下标或者当前下标对象是一个Object,就证明没有该数据,最终返回null,
/**
* Gets the Object mapped from the specified key, or <code>null</code>
* if no such mapping has been made.
*/
public E get(int key) {
return get(key, null);
}
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];
}
}