系列文章地址:
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
的映射缺點: