Google爲什麼建議使用 SpareArray代替HashMap

         在做android開發很多年的時間裏面,很多人都知道要使用 SpareArray,但是並不知道爲什麼。今天就來聊一聊SpareArray的實現源碼,講解下當前SpareArray的實現原理。

一、首先看下SpareArray的構造函數:

    public SparseArray() {
        this(10);
    }

    public SparseArray(int initialCapacity) {
        if (initialCapacity == 0) {
            mKeys = ContainerHelpers.EMPTY_INTS;
            mValues = ContainerHelpers.EMPTY_OBJECTS;
        } else {
            initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
            mKeys = new int[initialCapacity];
            mValues = new Object[initialCapacity];
        }
        mSize = 0;

    }

 默認是分配一個數組長度爲10,分別分配一個保存int類型的key,一個保存Object類型的值。

二、增加相應的數據
它有兩個方法可以添加鍵值對:
public void put(int key, E value)  
public void append(int key, E value)   

    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);
            }
            if (mSize >= mKeys.length) {
                int n = ArrayUtils.idealIntArraySize(mSize + 1);
                int[] nkeys = new int[n];
                Object[] nvalues = new Object[n];
                // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
                System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
                System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
                mKeys = nkeys;
                mValues = nvalues;
            }
            if (mSize - i != 0) {
                // Log.e("SparseArray", "move " + (mSize - i));
                System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
                System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
            }
            mKeys[i] = key;
            mValues[i] = value;
            mSize++;
        }

    }

     在上面添加數據的代碼中發現,裏面使用了一個非常重要的方法,就是二分查找法,來查找當前key的位置,然後,在適當的位置把當前值插入進去,因此,SparseArray添加的數組的內容一定是有序的。並且,它存儲的數值都是按鍵值從小到大的順序排列好的。其實append方法的實現方式和put的實現方式類似,這裏不再詳細講解。

三、查
它有兩個方法可以取值:
  1. public E get(int key)  
  2. public E get(int key, E valueIfKeyNotFound)  
最後一個從傳參的變量名就能看出,傳入的是找不到的時候返回的值
查看第幾個位置的鍵:
public int keyAt(int index)  
查看第幾個位置的值:
public E valueAt(int index)  
查看鍵所在位置,由於採用二分法查找鍵的位置,所以沒有的話返回小於0的數值,而不是返回-1,這點要注意,返回的負數其實是表示它在哪個位置就找不到了,如果你存了5個,查找的鍵大於5個值的話,返回就是-6:     public int indexOfKey(int key)  
查看值所在位置,沒有的話返回-1:
public int indexOfValue(E value)  

四、刪
它有兩個方法:
  1. public void delete(int key)  
  2. public void remove(int key)  
但其實,delete和remove的效果是一樣的,remove方法中調用了delete方法,remove源碼:public void remove(int key) {  
        delete(key);  
}  

還有一個clear方法,就是全部清除當前的所有數據。

通過上面的簡單分析,基本可以知道,SparseArray使用的是純數組的方式來實現的,不管是key,還是value都是一個數組。

而HashMap使用的是散列表(數組+鏈表)的方式實現的,查詢數據的計算方式也比數組要複雜。關於HashMap的實現原理,將在下一個章節中講解。另外,SparseArray實現了Cloneable接口,還可以調用clone方法。

對比當前的性能,總結如下:

1.SpareseArray 也是通過鍵值對存儲數據,只是key爲整形int , 類似於key = Interger 的HashMap,但是SpareseArray 的key 爲 int 非 Interger ,更省空間。
2. SpareArray 意爲稀鬆數組,其結構類似於數組結構,依次排開;HashMap是散列列表,根據hash值來存儲;因此SpareArray 會比 HashMap節省很多空間。
3.從查找速度 和 插入效率來看,如果是正序插入( 0 ->size插入),SpareArray 的插入效率會高於 HashMap。
4.如果是逆序插入(size -> 0)的順序插入,則SpareArray 的插入效率表現是最差的,會低於HashMap。
5. SpareArray 在逆序插入效率很低,是因爲 每次插入 SpareArray 都會採用二分查找來定位。
6. 從查找速度來來考慮,HashMap的查找速度 會 高於 SparseArray。
於是,通過以上分析,SpareArray 相對於 HashMap的最大優勢在內存空間。因此谷歌推薦使用 SpareArray 代替 HashMap 。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章