ArrayMap 和HashMap的區別


在以往android開發中,我們常常用key-value存儲數據時,隨手就會打出HashMap的代碼,當數據量較小時,這種方法還不錯還可以,當數據量比較多的時候,如果是PC機上,也還闊以。但是如果使用設備是手機等移動設備,這是就要慎重了。手機內存不像PC內存那樣,手機內存很寶貴,稍有不慎,可能就會引發OOM問題。那當數據量比較多,又需要在手機端開發,怎么解決內存問題呢?
       這個時候,我們就可以用ArrayMap替代HashMap。ArrayMap相比傳統的HashMap速度要慢,因為查找方法是二分法,並且當你刪除或者添加數據時,會對空間重新調整,在使用大量數據時,效率低於50%。可以說ArrayMap是犧牲了時間換區空間。但在寫手機app時,適時的使用ArrayMap,會給內存使用帶來可觀的提升。

那HashMap和ArrayMap到底不同在哪呢,主要有以下幾個方面:

1、存儲方式不同

HashMap內部有一個HashMapEntry<K, V>[]對象,每一個鍵值對都存儲在這個對象里,當使用put方法添加鍵值對時,就會new一個HashMapEntry對象,具體實現如下:

[java] view plaincopy
   @Override public V put(K key, V value) {
       if (key == null) {
           return putValueForNullKey(value);
       }
  
       int hash = secondaryHash(key);
       HashMapEntry<K, V>[] tab = table;
       int index = hash & (tab.length - 1);
    //先查找有沒有對應的key值,如果有,就改寫value,並返回改寫前的value值:oldValue
       for (HashMapEntry<K, V> 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;
               return oldValue;
           }
       }
  
       // No entry for (non-null) key is present; create one
       modCount++;
       if (size++ > threshold) {
        //擴容,雙倍
           tab = doubleCapacity();
           index = hash & (tab.length - 1);
       }
       addNewEntry(key, value, hash, index);
       return null;
   }
//創建對象存儲鍵值對
   void addNewEntry(K key, V value, int hash, int index) {
       table[index] = new HashMapEntry<K, V>(key, value, hash, table[index]);
   }

        ArrayMap的存儲中沒有Entry這個東西,他是由兩個數組來維護的
[java] view plaincopy
int[] mHashes;
Object[] mArray;

mHashes數組中保存的是每一項的HashCode值,mArray中就是鍵值對,每兩個元素代表一個鍵值對,前面保存key,后面的保存value,我們看看下面代碼的結果:
[java] view plaincopy
arraymap = new HashMap<String, String>();
a.put("a", "a_value");
a.put("b", "b_value");
執行上面代碼后,arraymap中的存儲是這樣的

 



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

[java] view plaincopy
mHashes[index] = hash;
mArray[index<<1] = key;
mArray[(index<<1)+1] = value;

2、添加數據時擴容時的處理不一樣

先來看看HashMap

[java] view plaincopy
if (size++ > threshold) {
    tab = doubleCapacity();
    index = hash & (tab.length - 1);
}

doubleCapacity進行雙倍擴容,它的代碼中有這么一句話
[java] view plaincopy
HashMapEntry<K, V>[] newTable = makeTable(newCapacity);

最終,這個newTable將作為擴容后的新對象返回,那么makeTable做了什么呢,如下:
[java] view plaincopy
private HashMapEntry<K, V>[] makeTable(int newCapacity) {
    @SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable
            = (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity];
    table = newTable;
    threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity
    return newTable;
}

我們清楚地看到,這里進行了new操作,重新創建對象,開銷很大。
那么ArrayMap呢,看看:

[java] view plaincopy
//如果容量不夠
ize >= mHashes.length) {
    final int n = 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);
  
    final int[] ohashes = mHashes;
    final Object[] oarray = mArray;
//分配數組
    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);
    }
        //釋放無用空間,收縮數組
    freeArrays(ohashes, oarray, mSize);
}

ArrayMap用的是copy數據,所以效率相對要高。

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

4、ArrayMap采用二分法查找;

以上就是android開發中,HashMap與ArrayMap的區別,大家在涉及到內存方面的實現,可根據實際情況選擇這兩種不同的方式。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM