1.将整数映射成对象(键值对),因为他不需要类似于HashMap进行装箱拆箱操作,所以内存效率优于HashMap;
2.使用二分法对于关键字进行查找(升序排列:类注释可知)
public E get(int key) {
return get(key, null);
}
@SuppressWarnings("unchecked")
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];
}
}
class ContainerHelpers {
// This is Arrays.binarySearch(), but doesn't do any argument validation.
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
}
static int binarySearch(long[] array, int size, long value) {
int lo = 0;
int hi = size - 1;
while (lo <= hi) {
final int mid = (lo + hi) >>> 1;
final long 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
}
}
3.由于Key和Value是通过数组存储的,所以,如果需要进行增删改查操作,那么就需要真实的进行移位删除操作,参考数组的增删改查,因此,会产生大量的性能开销,为此,故采用了延迟删除的操作
@UnsupportedAppUsage(maxTargetSdk = 28) // Use keyAt(int)
private int[] mKeys;
@UnsupportedAppUsage(maxTargetSdk = 28) // Use valueAt(int), setValueAt(int, E)
private Object[] mValues;
4.延迟删除,对于需要删除的操作,先把需要删除的元素标记起来,不做真正的删除,待到后续GC处理
5.通过查看GC源码可以得知,对于需要删除的已经被标记删除的元素,在gc方法处理时,也不会被真正的删除掉,但会处理原SparseArray的长度size,使需要删除的元素(延迟删除元素)在size以外,故永远不会被访问到,如果后续需要添加新的元素时,会被添加的元素覆盖掉
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
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;
// Log.e("SparseArray", "gc end with " + mSize);
}
之前没打算写,后来觉得,反正自己也记不住,不如写下来,自己忘了还能有个地方找,也不指望能帮到人,就只为能帮到我自己



