系列文章地址:
Android容器类-ArraySet原理解析(一)
Android容器类-ArrayMap原理解析(二)
Android容器类-SparseArray原理解析(三)
Android容器类-SparseIntArray原理解析(四)java
SparseArray
优化了int
到Object
键值对的存储,SparseIntArray
优化了int
到int
键值对的存储。android中在键值对存储上的优化主要作了一下几种类型的优化:android
int
--> Object
(SparseArray)int
--> int
(SparseIntArray)int
--> boolean
(SparseBooleanArray)int
--> long
(SparseLongArray)int
--> Set
(SparseSetArray)SparseSetArray目前在sdk中还处于hide状态,故在作总结的时候就不分析它了。数组
以前已经分析过SparseArray
,本文就分析下SparseIntArray
的实现,并在最后总结下这几种键值对在实现上的共同点。微信
以上为SparseIntArray
的继承体系。SparseIntArray
只实现了Cloneable
接口,结构比较简单。其实阅读源码能够发现,SparseArray
,SparseIntArray
,SparseBooleanArray
,SparseLongArray
都只实现了Cloneable
接口。ide
以上为SparseIntArray
的存储结构,mKeys存储的是int类型的键,mValues存储的是int类型的value。函数
// 查找键key在mKeys的下标
public int indexOfKey(int key) {
return ContainerHelpers.binarySearch(mKeys, mSize, key);
}
// 查找value在mValues的下标
public int indexOfValue(int value) {
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
复制代码
元素的查找分键查找和值查找,键查找使用二分查找,值查找直接使用循环遍历。优化
public void put(int key, int value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
复制代码
添加元素首先使用二分查找找到key在mKeys数组的下标,也就是value在mValues数组的下标。若是ContainerHelpers.binarySearch(mKeys,mSize,key)
在mKeys数组中没有找到key,则返回key待插入位置的下标的取反,若是找到了key,则直接更新mValues对应位置的值便可。 GrowingArrayUtils.insert
函数的实现以下:spa
public static int[] insert(int[] array, int currentSize, int index, int element) {
assert currentSize <= array.length;
if (currentSize + 1 <= array.length) {
System.arraycopy(array, index, array, index + 1, currentSize - index);
array[index] = element;
return array;
}
int[] newArray = ArrayUtils.newUnpaddedIntArray(growSize(currentSize));
System.arraycopy(array, 0, newArray, 0, index);
newArray[index] = element;
System.arraycopy(array, index, newArray, index + 1, array.length - index);
return newArray;
}
复制代码
函数的逻辑很简单,首先断言了currentSize <= array.length;若是array在不须要扩大容量的状况下能够添加一个元素,则先将待插入位置index开始的元素总体后移一位,而后插入元素,不然先扩容,而后将元素拷贝到新的数组中。.net
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
removeAt(i);
}
}
public void removeAt(int index) {
System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
System.arraycopy(mValues, index + 1, mValues, index, mSize - (index + 1));
mSize--;
}
复制代码
删除元素主要涉及以上两个方法,delete(int key)
根据key
进行删除,removeAt(int index)
删除指定下标的元素。这两个方法都是public
,故均可以直接使用。delete(int key)
,先使用二分查找,找到key
在mKeys
的下标,若是找到即i >= 0
,则直接删除mKeys
和mValues
指定位置的元素。设计
SparseBooleanArray
,SparseLongArray
尚未分析,他们的实现规则是同样的,只是存储的数据类型的mValues
数组是boolean
和 long
,接下来就对SparseIntArray
,SparseBooleanArray
,SparseLongArray
进行下总结。
int
到int
, boolean
,long
映射的存储int
类型的数组mKeys
存储映射的键,使用对应类型的数组mValues
存储值int
类型的键在存储上是有顺序的mKeys
中查找值在mValues
中的下标,而后返回值以上三种数据类型和SparseArray
最大的区别在于SparseArray
在删除元素的时候会将元素设置为DELETED
,后续会有gc
的过程。
相对于使用HashMap,这样的设计的优点和缺点:
优点:
int
类型的键自动装箱HashMap
使用Node
,这样的设计使用更小的存储单元便可存储key
到value
的映射缺点: