在做android开发很多年的时间里面,很多人都知道要使用 SpareArray,但是并不知道为什么。今天就来聊一聊SpareArray的实现源码,讲解下当前SpareArray的实现原理。
一、首先看下SpareArray的构造函数:
public SparseArray() {
this(10);
}
public SparseArray(int initialCapacity) {
if (initialCapacity == 0) {
mKeys = ContainerHelpers.EMPTY_INTS;
mValues = ContainerHelpers.EMPTY_OBJECTS;
} else {
initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
mKeys = new int[initialCapacity];
mValues = new Object[initialCapacity];
}
mSize = 0;
}
默认是分配一个数组长度为10,分别分配一个保存int类型的key,一个保存Object类型的值。
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
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);
}
if (mSize >= mKeys.length) {
int n = ArrayUtils.idealIntArraySize(mSize + 1);
int[] nkeys = new int[n];
Object[] nvalues = new Object[n];
// Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
mKeys = nkeys;
mValues = nvalues;
}
if (mSize - i != 0) {
// Log.e("SparseArray", "move " + (mSize - i));
System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
}
mKeys[i] = key;
mValues[i] = value;
mSize++;
}
}
在上面添加数据的代码中发现,里面使用了一个非常重要的方法,就是二分查找法,来查找当前key的位置,然后,在适当的位置把当前值插入进去,因此,SparseArray添加的数组的内容一定是有序的。并且,它存储的数值都是按键值从小到大的顺序排列好的。其实append方法的实现方式和put的实现方式类似,这里不再详细讲解。
- public E get(int key)
- public E get(int key, E valueIfKeyNotFound)
- public void delete(int key)
- public void remove(int key)
还有一个clear方法,就是全部清除当前的所有数据。
通过上面的简单分析,基本可以知道,SparseArray使用的是纯数组的方式来实现的,不管是key,还是value都是一个数组。
而HashMap使用的是散列表(数组+链表)的方式实现的,查询数据的计算方式也比数组要复杂。关于HashMap的实现原理,将在下一个章节中讲解。另外,SparseArray实现了Cloneable接口,还可以调用clone方法。
对比当前的性能,总结如下: