SimpleArrayMap
SimpleArrayMap 是 Andorid V4 包提供的一种用来代替 HashMap 的数据结构,由于 HashMap 在数据容量过大时时间复杂度会越来与趋近于 O(N) , 故而效率不高。SimpleArrayMap 的实现方式和工作过程使其内存占用更小,在数据量不大时效率更高,所以在 Android 开发中我们可以择机选择适合的方式来实现 Map
下面我们就来一步步分析,为什么 SimpleArrayMap 可以实现更小的内存占用和更加高效查找
一、成员变量
/**
* ArrayMap 扩容的最小数量
*/
private static final int BASE_SIZE = 4;
/**
* 缓存数组的最大数量,使用小的缓存数组可以避免垃圾回收
*/
private static final int CACHE_SIZE = 10;
// 缓存所用的数组,以及已经换的数量
static Object[] mBaseCache;
static int mBaseCacheSize;
static Object[] mTwiceBaseCache;
static int mTwiceBaseCacheSize;
/**
* 存放 key 的 hash 值的数组
*/
int[] mHashes;
/**
* 存放 key 和 value 的数组
*/
Object[] mArray;
/**
* 已存键值对的数量
*/
int mSize;
二、构造方法
/**
* 创建容量为空的 mHashes 和 mArray 数组
*/
public SimpleArrayMap() {
mHashes = ContainerHelpers.EMPTY_INTS;
mArray = ContainerHelpers.EMPTY_OBJECTS;
mSize = 0;
}
/**
* 根据给定的初始容量创建 mHashes 和 mArray 数组
*/
public SimpleArrayMap(int capacity) {
if (capacity == 0) {
mHashes = ContainerHelpers.EMPTY_INTS;
mArray = ContainerHelpers.EMPTY_OBJECTS;
} else {
allocArrays(capacity);
}
mSize = 0;
}
/**
* 根据给定的 ArrayMap 初始化
*/
public SimpleArrayMap(SimpleArrayMap map) {
this(); // 调用无参数构造函数
if (map != null) {
// 将给定的 ArrayMap 添加
putAll(map);
}
}
/**
* 将给定的 ArrayMap 添加本身
*/
public void putAll(SimpleArrayMap<? extends K, ? extends V> array) {
final int N = array.mSize;
// 确认容量支持添加给定的 ArrayMap
ensureCapacity(mSize + N);
if (mSize == 0) { // 如果原数组容量为 0,则将给定数组添加进新创建的数组中
if (N > 0) {
System.arraycopy(array.mHashes, 0, mHashes, 0, N);
System.arraycopy(array.mArray, 0, mArray, 0, N<<1);
mSize = N;
}
} else { // 如果原数组容量不为 0,则遍历给定数组,将给定数组的值添加到原数组中
for (int i=0; i<N; i++) {
put(array.keyAt(i), array.valueAt(i));
}
}
}
/**
* 确认容量支持指定的最小数量,如果当前容量小于指定的数量,则以给定数量创建新的数组
*/
public void ensureCapacity(int minimumCapacity) {
if (mHashes.length < minimumCapacity) {
final int[] ohashes = mHashes;
final Object[] oarray = mArray;
// 以给定容量创建新的数组
allocArrays(minimumCapacity);
if (mSize > 0) {
System.arraycopy(ohashes, 0, mHashes, 0, mSize);
System.arraycopy(oarray, 0, mArray, 0, mSize<<1);
}
// 缓存旧的 hash 数组
freeArrays(ohashes, oarray, mSize);
}
}
SimpleArrayMap 有三个重载的构造方法,其中给定容量和给定 ArrayMap 的构造方法中涉及到的方法我们下面回一一解析
三、插入方法 put()
public V put(K key, V value) {
final int hash;
int index;
if (key == null) {
hash = 0;
// 查找对应 key 在 hash 值数组中的位置
index = indexOfNull();
} else {
hash = key.hashCode();
// 查找对应 key 在 hash 值数组中的位置
index = indexOf(key, hash);
}
if (index >= 0) { // 存在,直接替换 array 数组中对应位置的 value 值,并将旧值返回
index = (index<<1) + 1;
final V old = (V)mArray[index];
mArray[index] = value;
return old;
}
index = ~index; // 未找到情况,需要执行插入操作
if (mSize >= mHashes.length) { // 为新插入数组需要扩容旧数组
final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1)) // 当前键值对数量大于等于最小扩容数量的 2 倍时,n 等于 mSeze 的 1.5 倍
: (mSize >= BASE_SIZE ? (BASE_SIZE*<