SparseIntArray、SparseArray、ArrayMap 和 HashMap 的原理分析

SparseIntArray、SparseArray、ArrayMap 和 HashMap 的原理分析

前言

Android開發(fā)一般都使用java集合里面的HashMap HashSet等集合API, 但是由于其特殊的需求做數(shù)據(jù)處理的時(shí)候,Android為自身定義了一套自有的API來實(shí)現(xiàn)本身的功能和需求,在android.util 里面有這幾個(gè)類: SparseArray(系列)、ArrayMap、 ArraySet等。

SparseArray的源碼分析

SparseArray(稀疏數(shù)組)是Android框架提供的工具類,用于建立整數(shù)和對(duì)象之間的映射關(guān)系,效果相當(dāng)于HashMap<Integer, Object>。SparseArray內(nèi)部采用了兩個(gè)數(shù)組分別存儲(chǔ)key-value, 尋找key的時(shí)候做二分查找。
1:SparseArray的定義的一些屬性

private static final Object DELETED = new Object();
private boolean mGarbage = false;
private int[] mKeys;
private Object[] mValues;
private int mSize;

1:DELETE: 所有被刪除的數(shù)據(jù)都會(huì)優(yōu)先指向這個(gè)對(duì)象
2:mGarbage: 是否進(jìn)行空間回收,true :立即執(zhí)行移除的操作
3:mKeys: 存儲(chǔ)Key的數(shù)組
4:mValues: 存儲(chǔ)value的數(shù)組
5:當(dāng)前元素的數(shù)量(不包含已經(jīng)被標(biāo)記刪除的元素)

2:構(gòu)造方法

public SparseArray() {    
    this(10);
}

/** * Creates a new SparseArray containing no mappings that will not 
* require any additional memory allocation to store the specified 
* number of mappings.  If you supply an initial capacity of 0, the 
* sparse array will be initialized with a light-weight representation 
* not requiring any additional array allocations.
*/
public SparseArray(int initialCapacity) {   
    if (initialCapacity == 0) {     
        mKeys = EmptyArray.INT;
        mValues = EmptyArray.OBJECT;
    } else {
        mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
        mKeys = new int[mValues.length];
    } 
    mSize = 0;
}

1: SparseArray存在兩個(gè)構(gòu)造方法, 帶參數(shù)的構(gòu)造方法可以指定SparseArray的初始容量,如果使用默認(rèn)的構(gòu)造函數(shù),那么初始容量為10。
2:當(dāng)初始容量為0的時(shí)候,mkey和mValue都被初始化了EmptyArray常量,避免重復(fù)創(chuàng)建

mKeys = EmptyArray.INT;
mValues = EmptyArray.OBJECT;

3: 當(dāng)初始容量不為0的時(shí)候,初始化 mValues 數(shù)組時(shí)使用了 ArrayUtils 的 newUnpaddedObjectArray 方法, 這是個(gè)native方法,此方法返回的就是一個(gè)比約定的容量大小大一些的容量。即: 實(shí)際返回的數(shù)組大小有可能比 minLength大,也就是說,如果 minLength 是15,那么實(shí)際返回的數(shù)組大小可能是 16。

3:SparseArray的增:
put 方法用于放入一個(gè)整數(shù)到對(duì)象的映射:


Image.png

1: binarySearch 二分查找來確定key的位置, 有效長度為mSize
2: 通過二分查找在 mKeys 數(shù)組的 mSize 長度中, 查看 key 是否已經(jīng)存在,如果存在,則直接更新 mValues 數(shù)組中對(duì)應(yīng)位置的值
3:key 不存在,那么將二分查找的返回值取反,得到 key 要插入的位置,檢查該位置的 value 是否標(biāo)記為已刪除,如果是,直接在該位置更新 key 和 value。
4:如果有必要,進(jìn)行一次「垃圾回收」,并更新即將插入的位置(垃圾回收過程數(shù)組元素發(fā)生了移動(dòng),所以插入位置可能會(huì)變動(dòng))
5:在 mKeys 和 mValues 數(shù)組中的對(duì)應(yīng)位置分別插入 key 和 value,size 加 1。

為什么將二分查找的返回值按位取反就能得到新元素的位置呢?
如果數(shù)組元素為 [-1,0,1,3,6], 如果數(shù)組元素為 [-1,0,1,3,6],在使用二分查找法查找元素 5 時(shí),lo 最后的值是4,也就是元素 5 應(yīng)該在數(shù)組中下標(biāo)為 4 的位置。在經(jīng)過按位取反后,binarySearch 的返回值就是個(gè)負(fù)數(shù)。而在 put 方法中,通過 i = ~i 可以得到這個(gè)位置下標(biāo),然后執(zhí)行更新或插入即可。

備注: 因?yàn)镵ey[] 和 value[] 初始值為null,所以在進(jìn)行put()操作的時(shí)候, 會(huì)優(yōu)先進(jìn)行一次二分查找進(jìn)行一下定位,那么key[]在進(jìn)行若干次put操作后就是一個(gè)有序的數(shù)組。

4: SparseArray的刪:remove and delete(都是public的類型)


Image1.png

delete方法首先使用二分查找對(duì)應(yīng)的key,取得到了對(duì)應(yīng)的位置,并未立即搬除數(shù)據(jù),而是把mValues對(duì)應(yīng)位置的元素指向delete, 并將mGarbage設(shè)置為true, 意味著有必要進(jìn)行垃圾回收了,當(dāng)下次垃圾回收的時(shí)候 再統(tǒng)一進(jìn)行元素的搬移操作。

5:SparseArray的查:


Image2.png

直接通過二分查找去查找key是否在mkey數(shù)組中, 如果有則返回mValues數(shù)組中的相同位置的值, 如果沒有或者mValues中對(duì)應(yīng)位置的元素被標(biāo)記為已刪除,就返回默認(rèn)值(沒有默認(rèn)值就返回為null)

SparseArray/ArrayMap 代替HashMap的優(yōu)點(diǎn)

1:SparseArray 相比 HashMap<Integer,Object> 主要做了兩點(diǎn)優(yōu)化:

一是避免了自動(dòng)裝箱過程,
二是去掉了額外的 Entry 包裝對(duì)象

2:SpareArray 內(nèi)部采用了兩個(gè)數(shù)組來分別存儲(chǔ) key 和 value,尋找 key 時(shí)使用了二分查找。不過,也是由于這個(gè)原因,查找效率無法和 HashMap 相比,適用于少量數(shù)據(jù)的情況。

3:ArrayMap系列跟HashMap的映射
SparseArray => HashMap<int, Object>
LongSparseArray => HashMap<long, Object>
SparseBooleanArray => HashMap<int, boolean>
SparseIntArray => HashMap<int, int>
SparseLongArray => HashMap<int, long>
ArrayMap => HashMap
ArraySet => HashSet

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容