為什么要用SparseArray來替換HashMap徘跪?

博文背景:

在Android 中使用HashMap 的時候看到過提示筹误。

HashMap<Integer,Object> mp = new HashMap<Integer,Object>(); 

提示:Use new SparseArray<Object>(...) instead for better performance意思是思犁,使用 SparseArray 將獲得更好的性能
(注:這個提示我再eclipse 中見過,而在studio 中并沒有看到過這種提示)

查閱網(wǎng)上資料關于SparseArray文檔介紹谋减,分析如下(ps:借鑒網(wǎng)上大佬的翻譯):

SparseArrays map integers to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more memory efficient than using a HashMap to map Integers to Objects, both because it avoids auto-boxing keys and its data structure doesn’t rely on an extra entry object for each mapping.

(譯文+個人理解)
SparseArrays不同于普通的對象數(shù)組。there can be gaps in the indices.(指針中能夠存在空白扫沼?注:這句我不太理解出爹,不知道怎樣翻譯庄吼,是說SparseArrays 是不連續(xù)存儲?)严就。它的目的是比使用從整數(shù)映射對象的HashMap(簡單來說就是 HashMap<Integer,Object>)有更有效的使用內(nèi)存总寻。

同一時候也避免auto-boxing(自己主動裝箱)(注:auto-boxing(自己主動裝箱):將原始類型封裝為對象類型。比方把int類型封裝成Integer類型梢为。)和數(shù)據(jù)結構對每條映射不依賴額外的Entry 對象(注:這里是和HashMap做的對照渐行。在HashMap有須要引入Entry<K,V>,而SparseArrays比較簡單,里面是兩個一維數(shù)組 int[] mKeys; 和 Object[] mValues)

Note that this container keeps its mappings in an array data structure, using a binary search to find keys. The implementation is not intended to be appropriate for data structures that may contain large numbers of items. It is generally slower than a traditional HashMap, since lookups require a binary search and adds and removes require inserting and deleting entries in the array. For containers holding up to hundreds of items, the performance difference is not significant, less than 50%.

注意抖誉,這個容器在數(shù)組數(shù)據(jù)結構中維持一個映射關系殊轴。使用二分查找法來找到key.它的目標不是為了適應數(shù)據(jù)結構中包括大量數(shù)據(jù)的情況。

通常情況下要比傳統(tǒng)的HashMap慢袒炉,由于查找是用二分查找法搜索旁理,加入和刪除須要對數(shù)組進行加入和刪除。

對于有幾百條的數(shù)據(jù)的容器我磁。性能差異不大孽文,不超過50%(注:這里我理解的是, SparseArrays 的優(yōu)勢更體如今小數(shù)量上)

To help with performance, the container includes an optimization when removing keys: instead of compacting its array immediately, it leaves the removed entry marked as deleted. The entry can then be re-used for the same key, or compacted later in a single garbage collection step of all removed entries. This garbage collection will need to be performed at any time the array needs to be grown or the the map size or entry values are retrieved.

為了提高性能夺艰,該容器提供了一個優(yōu)化:當刪除key鍵時芋哭。不是立刻刪除這一項,而是留下須要刪除的選項給一個刪除的標記郁副。

該條目能夠被又一次用于同樣的key,或者被單個垃圾收集器逐步刪除完所有的條目后壓縮减牺。在不論什么時候。當數(shù)組須要增長(注:這里我理解為 put存谎、append之類的操作)或者Map 的長度拔疚、entry的value須要被檢索的時候,該垃圾收集器就會運行(注:這里能夠從代碼中發(fā)現(xiàn)既荚。google在相應的方法中調(diào)用 gc() 方法)稚失。

It is possible to iterate over the items in this container using

  • {@link #keyAt(int)} and {@link #valueAt(int)}. Iterating over the keys using
  • keyAt(int) with ascending values of the index will return the
  • keys in ascending order, or the values corresponding to the keys in ascending
  • order in the case of valueAt(int).

在此使用此容器時,能夠迭代遍歷當中的item.. keyAt(int) 返回升序下的key .
valueAt(int) 返回升序狀態(tài)下恰聘。key 相應的value值句各。

與HashMap比較優(yōu)點?

key晴叨,value 類型的比較

HashMap | key:隨意類型 | value:隨意類型
SparseArray | key:Integer | value:隨意類型
SparseBooleanArray | key:Integer | value:Boolean類型凿宾。
SparseIntArray | key:Integer | value:Integer類型。
LongSparseArray | key:Long | value:隨意類型

依據(jù)需求的不同兼蕊,找到合適的方法才是上上策菌湃。

內(nèi)部存儲的比較

SparseArray |: int[] mkeys和 Object[] mvalues 來存儲key和value
HashMap | : 內(nèi)部存儲必須使用Entry<k,v>

其他分析

  • 創(chuàng)建數(shù)據(jù)

以10000條數(shù)據(jù)為例。HashMap用去約13.2M內(nèi)存遍略,SparseArray共用去 8.626M內(nèi)存惧所。

  • 數(shù)據(jù)插入

在正序插入數(shù)據(jù)時候骤坐,SparseArray比HashMap要快一些;HashMap無論是倒序還是正序開銷差點兒是一樣的下愈∨ι埽可是SparseArray的倒序插入要比正序插入要慢很多,為什么呢势似?
原因:SparseArray在檢索數(shù)據(jù)的時候使用的是二分查找拌夏,所以每次插入新數(shù)據(jù)的時候SparseArray都須要又一次排序,所以逆序是最差情況履因。

  • 數(shù)據(jù)檢索

SparseArray中存在須要檢索的下標時障簿。SparseArray的性能略勝一籌可是當檢索的下標比較離散時,SparseArray須要使用多次二分檢索栅迄,性能顯然比hash檢索方式要慢一些了站故。

  • 接口實現(xiàn)

    HashMap實現(xiàn)了Cloneable, Serializable SparseArray 實現(xiàn)了Cloneable 接口,也就是說SparseArray 是不支持序列化的。

  • 運行速度上比較毅舆,見大神分析:(傳送門)

源碼就不粘貼了西篓,分析部分代碼:

<pre><code>
/**

  • Adds a mapping from the specified key to the specified value,

  • replacing the previous mapping from the specified key if there

  • was one.
    通過指定的key和value加入一個鍵值對,假設這個位置已經(jīng)存在一個了,則替換掉
    */
    public void put(int key, E value) {
    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

    if (i >= 0) {
    mValues[i] = value;
    } else {
    i = ~i;

     if (i < mSize && mValues[i] == DELETED) {
         mKeys[i] = key;
         mValues[i] = value;
         return;
     }
    
     if (mGarbage && mSize >= mKeys.length) {
         gc();
    
         // Search again because indices may have changed.
         i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
     }
    
     mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
     mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
     mSize++;
    

    }
    }

/**

  • Puts a key/value pair into the array, optimizing for the case where
  • the key is greater than all existing keys in the array.
    通過指定的key和value加入一個鍵值對,在原有的基礎上添加
    */
    public void append(int key, E value) {
    if (mSize != 0 && key <= mKeys[mSize - 1]) {
    put(key, value);
    return;
    }
    </code></pre>

僅用于記錄備忘分享憋活,如有版權問題煩請私信岂津!謝謝

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市悦即,隨后出現(xiàn)的幾起案子吮成,更是在濱河造成了極大的恐慌,老刑警劉巖辜梳,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粱甫,死亡現(xiàn)場離奇詭異,居然都是意外死亡冗美,警方通過查閱死者的電腦和手機魔种,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進店門析二,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粉洼,“玉大人,你說我怎么就攤上這事叶摄∈羧停” “怎么了?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵蛤吓,是天一觀的道長宵喂。 經(jīng)常有香客問我,道長会傲,這世上最難降的妖魔是什么锅棕? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任拙泽,我火速辦了婚禮,結果婚禮上裸燎,老公的妹妹穿的比我還像新娘顾瞻。我一直安慰自己,他們只是感情好德绿,可當我...
    茶點故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布荷荤。 她就那樣靜靜地躺著,像睡著了一般移稳。 火紅的嫁衣襯著肌膚如雪蕴纳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天个粱,我揣著相機與錄音古毛,去河邊找鬼。 笑死几蜻,一個胖子當著我的面吹牛喇潘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播梭稚,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼颖低,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了弧烤?” 一聲冷哼從身側響起忱屑,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎暇昂,沒想到半個月后莺戒,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡急波,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年从铲,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片澄暮。...
    茶點故事閱讀 37,989評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡名段,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出泣懊,到底是詐尸還是另有隱情伸辟,我是刑警寧澤,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布馍刮,位于F島的核電站信夫,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜静稻,卻給世界環(huán)境...
    茶點故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一警没、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧振湾,春花似錦惠奸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至嵌言,卻和暖如春嗅回,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背摧茴。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工绵载, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人苛白。 一個月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓娃豹,卻偏偏與公主長得像,于是被迫代替她去往敵國和親购裙。 傳聞我的和親對象是個殘疾皇子懂版,可洞房花燭夜當晚...
    茶點故事閱讀 42,700評論 2 345

推薦閱讀更多精彩內(nèi)容