源码基于 API 25
主要参考文章:面试必备:ArrayMap源码解析
1、概述
在开始讲解源码之前,需要说明 ArrayMap 的底层实现结构,即两个数组:
int[] mHashes; // 用于存储 key 对应的 hash 值
Object[] mArray; // 根据映射规则,用于存储 key 和 value
其中,mHashes 按照 hash 值的大小从到大排序,这样就可以实现二分查找。
假设对于某一 key,有对应的 hash 值 X,如果 X 在 mHashes 中对应的下标为 index,则对于 mArray,mArray[index<<1]
存储着 key,mArray[(index<<1)+1]
存储着 value。
因此,mArray 的长度是 mHashes 的两倍。
2、成员及构造函数
// 用于缓存数组用的,后面会说到
static Object[] mBaseCache;
static int mBaseCacheSize;
static Object[] mTwiceBaseCache;
static int mTwiceBaseCacheSize;
// 判断通过 key 生成 hash 值时是否使用特殊的方法
final boolean mIdentityHashCode;
int[] mHashes;
Object[] mArray;
int mSize;
public ArrayMap() {
this(0, false);
}
/**
* Create a new ArrayMap with a given initial capacity.
*/
public ArrayMap(int capacity) {
this(capacity, false);
}
/** {@hide} */
public ArrayMap(int capacity, boolean identityHashCode) {
mIdentityHashCode = identityHashCode;
// If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
// instance instead of the usual EmptyArray.INT. The reference
// is checked later to see if the array is allowed to grow.
if (capacity < 0) {
mHashes = EMPTY_IMMUTABLE_INTS;
mArray = EmptyArray.OBJECT;
} else if (capacity == 0) {
mHashes = EmptyArray.INT;
mArray = EmptyArray.OBJECT;
} else {
// allocArrays() 方法用于构建指定容量的 mHashes 和 mArray
allocArrays(capacity);
}
mSize = 0;
}
/**
* Create a new ArrayMap with the mappings from the given ArrayMap.
*/
public ArrayMap(ArrayMap<K, V> map) {
this();
if (map != null) {
putAll(map);
}
}
3、成员方法
3.1 增
对于成员方法,其中,我认为 put(K key, V value)
方法是最先需要理解的,理解了 put()
,其他的就好理解了。
public V put(K key, V value) {
final int hash;
int index;
// 得到 key 的 hash 值,进一步的到该 hash 在 mHashes 中对应的 index
if (key == null) {
hash = 0;
index = indexOfNull();
} else {
// 根据 mIdentityHashCode 判断怎样生成 key 对应的 hash 值
hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
// indexOf() 方法用于根据 key 以及其 hash 值得到在 mHashes 中对应的 index
index = indexOf(key, hash);
}
// 如果 index >= 0,表示 key 已经存在,则直接替换对应位置的 value
if (index >= 0) {
index = (index<<1) + 1;
final V old = (V)mArray[index];
mArray[index] = value;
return old;
}
// 否则,该 key 原本没有,是需要新增的
// 因此 ~index 为需要新增插入的位置
index = ~index;
if (mSize >= mHashes.length) {
// 如果已经满了,则需要扩容
final int n = mSize >= (BASE_SIZE*2) ? (mSize+(mSize>>1))
: (mSize >= BASE_SIZE ? (BASE_SIZE