首页 > 代码库 > 性能优化:使用SparseArray代替HashMap<Integer,Object>
性能优化:使用SparseArray代替HashMap<Integer,Object>
HashMap是java里比较常用的一个集合类,我比较习惯用来缓存一些处理后的结果。最近在做一个Android项目,在代码中定义这样一个变量,实例化时,Eclipse却给出了一个 performance 警告。
意思就是说用SparseArray<E>来替代,以获取更好性能。老实说,对SparseArray并不熟悉,第一感觉应该是Android提供的一个类。按住Ctrl点击进入SparseArray的源码,果不其然,确定是Android提供的一个工具类。
单纯从字面上来理解,SparseArray指的是稀疏数组(Sparse array),所谓稀疏数组就是数组中大部分的内容值都未被使用(或都为零),在数组中仅有少部分的空间使用。因此造成内存空间的浪费,为了节省内存空间,并且不影响数组中原有的内容值,我们可以采用一种压缩的方式来表示稀疏数组的内容。
假设有一个9*7的数组,其内容如下:
在此数组中,共有63个空间,但却只使用了5个元素,造成58个元素空间的浪费。以下我们就使用稀疏数组重新来定义这个数组:
其中在稀疏数组中第一部分所记录的是原数组的列数和行数以及元素使用的个数、第二部分所记录的是原数组中元素的位置和内容。经过压缩之后,原来需要声明大小为63的数组,而使用压缩后,只需要声明大小为6*3的数组,仅需18个存储空间。
继续阅读SparseArray的源码,从构造方法我们可以看出,它和一般的List一样,可以预先设置容器大小,默认的大小是10:
- public SparseArray() {
- this(10);
- }
- public SparseArray(int initialCapacity) {
- initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
- mKeys = new int[initialCapacity];
- mValues = new Object[initialCapacity];
- mSize = 0;
- }
它有两个方法可以添加键值对:
- public void put(int key, E value) {}
- public void append(int key, E value){}
- public void delete(int key) {}
- public void remove(int key) {} //直接调用的delete(int key)
- public void removeAt(int index){}
- public void clear(){}
- public void put(int key, E value) {
- int i = binarySearch(mKeys, 0, 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 = ~binarySearch(mKeys, 0, mSize, key);
- }
- …………
- public void put(int key, E value)
- public void setValueAt(int index, E value)
- public E get(int key)
- public E get(int key, E valueIfKeyNotFound)
查看第几个位置的键:
- public int keyAt(int index)
查看第几个位置的值:
- public E valueAt(int index)
1 | public int indexOfValue(E value) |
最后,发现其核心就是折半查找函数(binarySearch),算法设计的很不错。
1 | private static int binarySearch(int[] a,int start, int len, intkey) { |
2 | inthigh = start + len, low = start - 1, guess; |
3 |
4 | while(high - low > 1) { |
5 | guess = (high + low) /2; |
6 |
7 | if(a[guess] < key) |
8 | low = guess; |
9 | else |
10 | high = guess; |
11 | } |
12 |
13 | if(high == start + len) |
14 | return~(start + len); |
15 | elseif (a[high] == key) |
16 | returnhigh; |
17 | else |
18 | return~high; |
19 | } |
相应的也有SparseBooleanArray,用来取代HashMap<Integer, Boolean>,SparseIntArray用来取代HashMap<Integer, Integer>,大家有兴趣的可以研究。
总结:SparseArray是android里为<Interger,Object>这样的Hashmap而专门写的类,目的是提高效率,其核心是折半查找函数(binarySearch)。在Android中,当我们需要定义
1 | HashMap<Integer, E> hashMap = new HashMap<Integer, E>(); |
时,我们可以使用如下的方式来取得更好的性能。
1 | SparseArray<E> sparseArray = new SparseArray<E>(); |
性能优化:使用SparseArray代替HashMap<Integer,Object>