SparseArray採用時間換取空間的方式來提升手機App的運行效率,這也是其與HashMap的區別;HashMap經過空間換取時間,查找迅速;HashMap中當table數組中內容達到總容量0.75時,則擴展爲當前容量的兩倍,關於HashMap可查看HashMap實現原理學習)android
下邊對其源碼進行簡單學習。數組
// 構造方法 public SparseArray() { this(10); } // 構造方法 public SparseArray(int initialCapacity) { if (initialCapacity == 0) { mKeys = EmptyArray.INT; mValues = EmptyArray.OBJECT; } else { // key value各自爲一個數組,默認長度爲10 mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity); mKeys = new int[mValues.length]; } mSize = 0; }
ps:
SparseArray構造方法中,建立了兩個數組mKeys、mValues分別存放int與Object,其默認長度爲10學習
public void put(int key, E value) { // 二分查找,key在mKeys列表中對應的index int i = ContainerHelpers.binarySearch(mKeys, mSize, key); // 若是找到,則直接賦值 if (i >= 0) { mValues[i] = value; } // 找不到 else { // binarySearch方法中,找不到時,i取了其非,這裏再次取非,則非非則正 i = ~i; // 若是該位置的數據正好被刪除,則賦值 if (i < mSize && mValues[i] == DELETED) { mKeys[i] = key; mValues[i] = value; return; } // 若是有數據被刪除了,則gc if (mGarbage && mSize >= mKeys.length) { gc(); // Search again because indices may have changed. i = ~ContainerHelpers.binarySearch(mKeys, mSize, key); } // 插入數據,增加mKeys與mValues列表 mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key); mValues = GrowingArrayUtils.insert(mValues, mSize, i, value); mSize++; } }
ps:this
// 經過key查找對應的value public E get(int key) { return get(key, null); } // 經過key查找對應的value public E get(int key, E valueIfKeyNotFound) { // mKeys數組中採用二分查找,找到key對應的index int i = ContainerHelpers.binarySearch(mKeys, mSize, key); // 沒有找到,則返回空 if (i < 0 || mValues[i] == DELETED) { return valueIfKeyNotFound; } else { // 找到則返回對應的value return (E) mValues[i]; } }
ps:
每次調用get,則需通過一次mKeys數組的二分查找,所以mKeys數組越大則二分查找的時間就越長,所以SparseArray在大量數據,千以上時,會效率較低spa
// array爲有序數組 // size數組中內容長度 // value要查找的值 static int binarySearch(int[] array, int size, int value) { int lo = 0; int hi = size - 1; // 循環查找 while (lo <= hi) { // 取中間位置元素 final int mid = (lo + hi) >>> 1; final int midVal = array[mid]; // 若是中間元素小於要查找元素,則midIndex賦值給 lo if (midVal < value) { lo = mid + 1; } // 若是中間元素大於要查找元素,則midIndex賦值給 hi else if (midVal > value) { hi = mid - 1; } // 找到則返回 else { return mid; // value found } } // 找不到,則lo 取非 return ~lo; // value not present }
ArrayMap和SparseArray有點相似;其中含有兩個數組,一個是mHashes(key的hash值數組,爲一個有序數組),另外一個數組存儲的是key和value,其中key和value是成對出現的,key存儲在數組的偶數位上,value存儲在數組的奇數位上。.net
public SimpleArrayMap() { // key的hash值數組,爲一個有序數組 mHashes = ContainerHelpers.EMPTY_INTS; // key 與 value數組 mArray = ContainerHelpers.EMPTY_OBJECTS; mSize = 0; }
ps:
構造方法中初始化了兩個數組mHashes、mArray,其中mHashes爲key的Hash值對應的數組code
public V put(K key, V value) { // key 對應的hash值 final int hash; // hash對應的mHashes列表的index int index; // key爲空,hash爲0 if (key == null) { hash = 0; index = indexOfNull(); } // else { // 計算key的hashcode hash = key.hashCode(); // 查找key對應mHashes中的index,大於0則找到了,不然爲未找到 // 這裏涉及到hash衝突,若是hash衝突,則在index的相鄰位置插入數據 index = indexOf(key, hash); } // 找到key對應mHashes中的index if (index >= 0) { // 取出基數位置原有的Value index = (index<<1) + 1; final V old = (V)mArray[index]; // 將新數據放到基數index位置 mArray[index] = value; return old; } // indexOf中取了反,這裏反反則正 index = ~index; // 若是滿了就擴容 if (mSize >= mHashes.length) { final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)) : (mSize >= BASE_SIZE ? (BASE_SIZE*2) : BASE_SIZE); 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"); System.arraycopy(ohashes, 0, mHashes, 0, ohashes.length); System.arraycopy(oarray, 0, mArray, 0, oarray.length); } freeArrays(ohashes, oarray, mSize); } // 根據上面的二分法查找,若是index小於mSize,說明新的數據是插入到數組之間index位置,插入以前須要把後面的移位 if (index < mSize) { if (DEBUG) Log.d(TAG, "put: move " + index + "-" + (mSize-index) + " to " + (index+1)); System.arraycopy(mHashes, index, mHashes, index + 1, mSize - index); System.arraycopy(mArray, index << 1, mArray, (index + 1) << 1, (mSize - index) << 1); } // 保存數據 mHashes[index] = hash; mArray[index<<1] = key; mArray[(index<<1)+1] = value; mSize++; return null; }
// 根據key 與key的hash,查找key對應的index int indexOf(Object key, int hash) { final int N = mSize; // Important fast case: if nothing is in here, nothing to look for. if (N == 0) { return ~0; } // 二分查找mHashes有序數組,查找hash對應的index int index = ContainerHelpers.binarySearch(mHashes, N, hash); // 沒有找到 if (index < 0) { return index; } // 偶數位爲對應的key,則找到了 if (key.equals(mArray[index<<1])) { return index; } // index以後查找 // 這裏涉及到hash衝突,若是hash衝突,則在index的相鄰位置插入數據 // Search for a matching key after the index. int end; for (end = index + 1; end < N && mHashes[end] == hash; end++) { if (key.equals(mArray[end << 1])) return end; } // index以前查找 // Search for a matching key before the index. for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) { if (key.equals(mArray[i << 1])) return i; } // 沒有找到 return ~end; }