Android4.4之后推出的ArrayMap集合詳解

通常我們?cè)谑褂胟ey-value存儲(chǔ)數(shù)據(jù)時(shí),隨手就會(huì)打出HashMap的代碼,當(dāng)數(shù)據(jù)量較小時(shí),還可以,當(dāng)數(shù)量比較多的時(shí)候,如果是PC機(jī)上,也還說得過去,但是如果使用設(shè)備是手機(jī)等移動(dòng)設(shè)備,這是就要慎重了。因?yàn)槭謾C(jī)的內(nèi)存非常寶貴,不像PC那樣不計(jì)后果的使用,內(nèi)存使用不當(dāng)很容易就會(huì)引起OOM的問題。那Android開發(fā)團(tuán)隊(duì),也為我們找到了HashMap的替代品ArrayMap。

官方對(duì)ArrayMap也有說明:它不是一個(gè)適應(yīng)大數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),相比傳統(tǒng)的HashMap速度要慢,因?yàn)椴檎曳椒ㄊ嵌址?,并且?dāng)你刪除或者添加數(shù)據(jù)時(shí),會(huì)對(duì)空間重新調(diào)整,在使用大量數(shù)據(jù)時(shí),效率并不明顯,低于50%。

所以ArrayMap是犧牲了時(shí)間換區(qū)空間。在寫手機(jī)app時(shí),適時(shí)的使用ArrayMap,會(huì)給內(nèi)存使用帶來可觀的提升。

那HashMap和ArrayMap到底不同在哪呢,個(gè)人總結(jié)有以下方面:

1、存儲(chǔ)方式不同。

HashMap內(nèi)部有一個(gè)HashMapEntry[]對(duì)象,每一個(gè)鍵值對(duì)都存儲(chǔ)在這個(gè)對(duì)象里,當(dāng)使用put方法添加鍵值對(duì)時(shí),就會(huì)new一個(gè)HashMapEntry對(duì)象

[java]view plaincopy

@OverridepublicV?put(K?key,?V?value)?{

if(key?==null)?{

returnputValueForNullKey(value);

}

inthash?=?secondaryHash(key);

HashMapEntry[]?tab?=?table;

intindex?=?hash?&?(tab.length?-1);

//先查找有沒有對(duì)應(yīng)的key值,如果有,就改寫value,并返回改寫前的value值:oldValue

for(HashMapEntry?e?=?tab[index];?e?!=null;?e?=?e.next)?{

if(e.hash?==?hash?&&?key.equals(e.key))?{

preModify(e);

V?oldValue?=?e.value;

e.value?=?value;

returnoldValue;

}

}

//?No?entry?for?(non-null)?key?is?present;?create?one

modCount++;

if(size++?>?threshold)?{

//擴(kuò)容,雙倍

tab?=?doubleCapacity();

index?=?hash?&?(tab.length?-1);

}

addNewEntry(key,?value,?hash,?index);

returnnull;

}

//創(chuàng)建對(duì)象存儲(chǔ)鍵值對(duì)

voidaddNewEntry(K?key,?V?value,inthash,intindex)?{

table[index]?=newHashMapEntry(key,?value,?hash,?table[index]);

}

ArrayMap的存儲(chǔ)中沒有Entry這個(gè)東西,他是由兩個(gè)數(shù)組來維護(hù)的

[java]view plaincopy

int[]?mHashes;

Object[]?mArray;

mHashes數(shù)組中保存的是每一項(xiàng)的HashCode值,mArray中就是鍵值對(duì),每?jī)蓚€(gè)元素代表一個(gè)鍵值對(duì),前面保存key,后面的保存value,我們看看下面代碼的結(jié)果

[java]view plaincopy

arraymap?=newHashMap();

a.put("a","a_value");

a.put("b","b_value");

執(zhí)行上面代碼后,arraymap中的存儲(chǔ)是這樣的

是不是能清楚地看到ArrayMap的存儲(chǔ)了,這種存儲(chǔ)在put代碼中如下

[java]view plaincopy

mHashes[index]?=?hash;

mArray[index<<1]?=?key;

mArray[(index<<1)+1]?=?value;

2、添加數(shù)據(jù)時(shí)擴(kuò)容時(shí)的處理不一樣

先來看看HashMap

[java]view plaincopy

if(size++?>?threshold)?{

tab?=?doubleCapacity();

index?=?hash?&?(tab.length?-1);

}

doubleCapacity進(jìn)行雙倍擴(kuò)容,它的代碼中有這么一句話

[java]view plaincopy

HashMapEntry[]?newTable?=?makeTable(newCapacity);

最終,這個(gè)newTable將作為擴(kuò)容后的新對(duì)象返回,那么makeTable做了什么呢,如下:

[java]view plaincopy

privateHashMapEntry[]?makeTable(intnewCapacity)?{

@SuppressWarnings("unchecked")?HashMapEntry[]?newTable

=?(HashMapEntry[])newHashMapEntry[newCapacity];

table?=?newTable;

threshold?=?(newCapacity?>>1)?+?(newCapacity?>>2);//?3/4?capacity

returnnewTable;

}

我們清楚地看到,這里進(jìn)行了new操作,重新創(chuàng)建對(duì)象,開銷很大。

那么ArrayMap呢,看看吧

[java]view plaincopy

//如果容量不夠

ize?>=?mHashes.length)?{

finalintn?=?mSize?>=?(BASE_SIZE*2)???(mSize+(mSize>>1))

:?(mSize?>=?BASE_SIZE???(BASE_SIZE*2)?:?BASE_SIZE);

if(DEBUG)?Log.d(TAG,"put:?grow?from?"+?mHashes.length?+"?to?"+?n);

finalint[]?ohashes?=?mHashes;

finalObject[]?oarray?=?mArray;

//分配數(shù)組

allocArrays(n);

if(mHashes.length?>0)?{

if(DEBUG)?Log.d(TAG,"put:?copy?0-"+?mSize?+"?to?0");

//特別注意這,是copy,而不是new,效率提升

System.arraycopy(ohashes,0,?mHashes,0,?ohashes.length);

System.arraycopy(oarray,0,?mArray,0,?oarray.length);

}

//釋放無用空間,收縮數(shù)組

freeArrays(ohashes,?oarray,?mSize);

}

ArrayMap用的是copy數(shù)據(jù),所以效率相對(duì)要高。

3、ArrayMap提供了數(shù)組收縮的功能,在clear或remove后,會(huì)重新收縮數(shù)組,是否空間

4、ArrayMap采用二分法查找(見 android.support.v4.util.ContainerHelpers中的binarySearch方法)

?著作權(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),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 一、基本數(shù)據(jù)類型 注釋 單行注釋:// 區(qū)域注釋:/* */ 文檔注釋:/** */ 數(shù)值 對(duì)于byte類型而言...
    龍貓小爺閱讀 4,455評(píng)論 0 16
  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,921評(píng)論 0 33
  • 宣堡,又稱宣家堡;在宣堡郊區(qū),聳立著一個(gè)巍峨高大的牌匾刻著“宣家堡”;我的那個(gè)他用地道的方言告訴我,叫“宣嘎堡”。...
    三末閱讀 620評(píng)論 0 1
  • 這本書其實(shí)是讓我有些失望的,也有可能是期望過高了些。 其實(shí)在看《挪威的森林》時(shí),盡管故事講述的是主角渡邊糾纏在情緒...
    七筒妹妹閱讀 946評(píng)論 0 0
  • 生活是件細(xì)碎的事 在千千細(xì)碎中是否有一片是我對(duì)你的牽掛 是否有一種羈絆在你碌碌中沉寂 又在某個(gè)午夜夢(mèng)回時(shí)給你清醒的...
    南方的茶閱讀 190評(píng)論 0 0

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