SparseArray
中文名字是稀疏數組。
SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more efficient than using a HashMap to map Integers to Objects.
從它的源碼隨處可以看到,它採用了二分法(binarySearch)來存儲和查找數據。
看了上面一點資料之後,我並不認爲它的性能會比Hashmap的要好。hashmap畢竟能夠大約O(1)的時間查找到對象。而這個稀疏數組卻要二分才能找到目標。
-------------------------------
使用SparseArray有兩個好處。
1、使用hashmap的時候,我們需要這麼樣聲明:
HashMap<Integer, String> m=new HashMap<Integer, String>();
從上面這行代碼以看到,map中,將一個整數映射到一個Object的時候,是需要自動裝箱拆箱的(性能的浪費)。而SparseArray不需要。SparseArray的key直接就是int。
看key的聲明:
private int[] mKeys;
2、手持設備一般是內存受限的。Hashmap雖然查找性能好,但是map有一個問題就是浪費內存。而SparseArray雖然查找效率是O(logn)的,但是,,,,先看一下SparseArray的源碼中gc函數:
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);
}
這個函數“回收”SparseArray中已經“DELETED”的元素。設置它們爲NULL。從這點我們可以看到,SparseArray在刪除元素的時候,並不是真正的刪除。而是將相應的位置上置爲“DELETED”,然後在某個時間再去“gc”,設置爲null。這就是爲什麼SparseArray的api上描述,Unlike a normal array of Objects, there can be gaps in the indices,這些gaps就是gc的時候設置爲null的地方了。gc的時候,會將SparseArray中維護的數組內容向前移動(for語句中的那三句賦值操作)。這樣就把gaps消除了。每次gc,都能把之前設置爲DELETED的部分消除。那麼,數組後邊的元素移動到前面了,後面空出來的空間怎麼處理?從它源碼中也是隨處可看到這麼一句:
int n = ArrayUtils.idealIntArraySize(mSize + 1);
這句話就是分配數組大小。然後在put等添加操作的時候,用新申請的數組放置元素,原來的數組等待JVM來回收。
下面看一下idealIntArraySize函數的實現:
所以每次ArrayUtils分配數組大小的時候,會“酌情”考慮比need多分配一些空間。從而讓數組不是那麼容易就要因爲增加內容而再次分配空間。
-----------------------------------------------------
另外要注意的是,它是線程不安全的。
相對map來說,SparseArray能節省內存。