1.功能
SparseArray功能与于HashMap相同,就是以key-value的形式存储键值对
SparseArray<T> key:int value: T
LongSparseArray<T> key:long value: T 存在的意义是弥补SparseArray key的长度
SparseBooleanArray key:int value: boolean 基础类型的“map”
SparseLongArray key:int value: long 基础类型的“map”
SparseIntArray key:int value: int 基础类型的“map”
2.实现
Sparse的实现代码都很短,几百行左右。
类开头表明这其实不是一个map,而是维护了两个数组,也就是说操作sparse所有的操作,其实就是操作数组。
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object();//value的临时占位对象,好处是不用每次删除要压缩
//移除元素时标记位置为true,
//下次获取数组信息时需要对数组进行“gc”操作,其实就是对数组重新进行排序及纠正mSize的值
private boolean mGarbage = false;
private int[] mKeys; //key数组
private Object[] mValues; //value数组
private int mSize; //
put方法
public void put(int key, E value) {
//二分查找是否有此key,有则返回正常key,没有则返回负
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
//i小于数组长度,且i处的value已删除,则可直接进行赋值
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
if (mGarbage && mSize >= mKeys.length) {//需要数组纠偏
gc();
// 二分查找。
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);//其实就是数组拷贝扩容
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);//一样的
mSize++;
}
}
get方法
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];
}
}
remove方法
public void delete(int key) {
//熟悉的二分查找
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;//该位置置为占位对象
mGarbage = true; //压缩标记位置为true,下次操作前对数组进行压缩处理。
}
}
}
3.性能主要与HashMap对比
- 占用内存小,会比HashMap占用少15-25%;
- 避免自动装箱
- 查找效率方面,在数据量较小的情况下差距不明显,数据量较大的时候,效率还是map更快一些,总体差距并不是很大。
- 总体而言,算是牺牲效率较少内存。
4.总结一下
虽然都把SparseArray当成终端的一种内存优化手段,但前提是终端的硬件条件较差,牺牲点效率换取内存占用,官方都说提高不会超过50%,优化的收效甚微。^_^