ArrayMap及SparseArray是android的系统API,是专门为移动设备而定制的。用于在一定情况下取代HashMap而达到节省内存的目的。本文将从源码的角度来分析ArrayMap与SpareArray的实现原理,了解他们与HashMap之间的差别。首先来看ArrayMap的源码。
一、ArrayMap
1.简介
ArrayMap是一个通用的key-value映射关系,它的映射存储在数组数据结构中。一个int数组用来存储每一项的hashcode值,一个Object数组用来存储key-value对。
ArrayMap查找是通过二分查找来实现的,ArrayMap数组容量不会自动收缩的。
ArrayMap利用两个数组,mHashes用来保存每一个key的hash值,mArrray大小为mHashes的2倍,依次保存key和value。
当插入时,根据key的hashcode()方法得到hash值,然后根据key和hash值计算出在mHashes数组中的index位置,具体是先通过二分查找找到对应的位置,当出现哈希冲突时,则会在index的相邻位置插入。
时间效率上看,插入和查找的时候因为都用的二分法,查找的时候应该是没有hash查找快,插入的时候呢,如果顺序插入的话效率肯定高,但如果是随机插入,肯定会涉及到大量的数组搬移,数据量大,肯定不行。
2.源码分析
public final class ArrayMap<K, V> implements Map<K, V> {
int[] mHashes;//保存key的hash值的int数组
Object[] mArray;//保存key-value的Object数组
int mSize;//元素的个数
}
ArrayMap是实现了Map接口的,里面有两个数组,一个是保存key的hash值的int数组,另外一个是保存key-value的Object数组。size是来表示存储元素的个数。
2.1 构造方法
/*
* 创建一个空的ArrayMap
*/
public ArrayMap() {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
mSize = 0;
}
/*
* 创建一个容量为capability大小的ArrayMap
*/
public ArrayMap(int capacity) {
if (capacity == 0) {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
} else {
allocArrays(capacity);
}
mSize = 0;
}
ArrayMap有两个构造函数,一个是默认构造函数,容量为0,数组是空的。另外一个是带容量的构造函数,并且给数组分配容量。
private void allocArrays(final int size) {
if (mHashes == EMPTY_IMMUTABLE_INTS) {
throw new UnsupportedOperationException("ArrayMap is immutable");
}
if (size == (BASE_SIZE*2)) {
synchronized (ArrayMap.class) {
if (mTwiceBaseCache != null) {
final Object[] array = mTwiceBaseCache;
mArray = array;
mTwiceBaseCache = (Object[])array[0];
mHashes = (int[])array[1];
array[0] = array[1] = null;
mTwiceBaseCacheSize--;
if (DEBUG) Log.d(TAG, "Retrieving 2x cache " + mHashes
+ " now have " + mTwiceBaseCacheSize + " entries");
return;
}
}
} else if (size == BASE_SIZE) {
synchronized (ArrayMap.class) {
if (mBaseCache != null) {
final Object[] array = mBaseCache;
mArray = array;
mBaseCache = (Object[])array[0];
mHashes = (int[])array[1];
array[0] = array[1] = null;
mBaseCacheSize--;
if (DEBUG) Log.d(TAG, "Retrieving 1x cache " + mHashes
+ " now have " + mBaseCacheSize + " entries");
return;
}
}
}
//hash数组的大小为size
mHashes = new int[size];
//key-value数组的大小为2倍的size,因为包含了key和value
mArray = new Object[size<<1];
}
2.2 添加元素
将一个key-value添加到ArrayMap集合中的方法如下:
/*
* 将一个key-value对添加到ArrayMap中
*/
public V put(K key, V value) {
final int hash;
int index;
//key值为null的情况
if (key == null) {
hash = 0;
index = indexOfNull();
} else {
//计算key的hash值
hash = key.hashCode();
//根据key的hash值二分查找hash值对应的索引
index = indexOf(key, hash);
}
//如果index大于0,说明已经存在该key了,则直