SparseArray介绍

jopen 9年前

首先说一下SparseArray是什么东西,在java中我们也没见过这个API啊,哦,原来是android中定义的一个类,按字面意思来说是一个稀疏数组,但通过源码注释我们发现它和数组有很大的区别:

 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.

我们通过这段注释大体知道,android希望我们用SparseArray在一些情况下代替HashMap来使用,因为它有更好的性能,大家都知道内存是非常宝贵的,尤其是在手机上。

再看一下它的两个构造函数:

/**   * Creates a new SparseArray containing no mappings.   */  public SparseArray() {      this(10);  }    /**   * Creates a new SparseArray containing no mappings that will not   * require any additional memory allocation to store the specified   * number of mappings.  If you supply an initial capacity of 0, the   * sparse array will be initialized with a light-weight representation   * not requiring any additional array allocations.   */  public SparseArray(int initialCapacity) {      if (initialCapacity == 0) {          mKeys = EmptyArray.INT;          mValues = EmptyArray.OBJECT;      } else {          mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);          mKeys = new int[mValues.length];      }      mSize = 0;  }

发现其默认的key-value数组大小是10,当然也可以是自定义的。

SparseArray中有一些和HashMap中相似的实用方法,比如:

put(int key, E value)  get(int key)  get(int key, E valueIfKeyNotFound)  delete(int key)  removeAt(int index)  keyAt(int index)  valueAt(int index)  等等。

随便分析一个方法,比如put(int key,E value):

/**   * Adds a mapping from the specified key to the specified value,   * replacing the previous mapping from the specified key if there   * was one.   */  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++;      }  }

代码中首先查询该key在SparseArray中是否已经存在,若存在,替换掉,若不存在,把对应的key和value插入到对应的数组中,然后mSize++。大家注意到在查询key时使用的折半查找,看源码:

class ContainerHelpers {        // This is Arrays.binarySearch(), but doesn't do any argument validation.      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];                if (midVal < value) {                  lo = mid + 1;              } else if (midVal > value) {                  hi = mid - 1;              } else {                  return mid;  // value found              }          }          return ~lo;  // value not present      }        static int binarySearch(long[] array, int size, long value) {          int lo = 0;          int hi = size - 1;            while (lo <= hi) {              final int mid = (lo + hi) >>> 1;              final long midVal = array[mid];                if (midVal < value) {                  lo = mid + 1;              } else if (midVal > value) {                  hi = mid - 1;              } else {                  return mid;  // value found              }          }          return ~lo;  // value not present      }  }

哇哦,是不是我们在java中常用的一种查找方式。

知道了这些之后,我们以后就可以使用SparseArray来代替HashMap了,但是要注意SparseArray中的key是int类型,若实际中不是int类型,还得乖乖的使用map,另外,根据key-value中的value类型不同,android又给封装了SparseIntArray,SparseBooleanArray,SparseLongArray等等,使用方法和SparseArray都大同小异,只要你会使用Map,那么你就会使用SparseArray。

来自: http://my.oschina.net/gef/blog/600698