//實現了Cloneable接口
public class SparseArray<E> implements Cloneable {
private static final Object DELETED = new Object(); //DELETED對象,用來指示被刪除的對象
private boolean mGarbage = false;//指示是否垃圾回收
private int[] mKeys;//保存key值的數組
private Object[] mValues;//保存value值的數組
private int mSize;//當前SparseArray的大小
//構造函數,默認元素數量爲10個
public SparseArray() {
this(10);
}
//帶Capacity的構造函數,當Capacity爲0時,不限定數組的大小
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;
}
}
//clone接口,實現key數組和value數組的拷貝
public SparseArray<E> clone() {
SparseArray<E> clone = null;
try {
clone = (SparseArray<E>) super.clone();
clone.mKeys = mKeys.clone();
clone.mValues = mValues.clone();
} catch (CloneNotSupportedException cnse) {
/* ignore */
}
return clone;
}
//從指定的key值獲取映射的Object
public E get(int key) {
return get(key, null);
}
public E get(int key, E valueIfKeyNotFound) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);//二分查找key值對應的索引值i
//當索引值i小於0,或者值是被標記爲刪除時,返回valueIfKeyNotFound
if (i < 0 || mValues[i] == DELETED) {
return valueIfKeyNotFound;
} else {
return (E) mValues[i];
}
}
//將指定key對應的Value對象標記爲DELETED刪除
public void delete(int key) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
if (mValues[i] != DELETED) {
mValues[i] = DELETED;
mGarbage = true;
}
}
}
//與delete方法具有相同的功能
public void remove(int key) {
delete(key);
}
//移除指定索引的Value對象
public void removeAt(int index) {
if (mValues[index] != DELETED) {
mValues[index] = DELETED;
mGarbage = true;
}
}
//回收被標記DELETE的對象,將數組向前壓縮
private void gc() {
int n = mSize;
int o = 0;
int[] keys = mKeys;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
Object val = values[i];
//如果val不等於DELETED對象,i和o都整體往後移動,否則只讓i後移,這樣DELETE對象會被後面的對象覆蓋,DELETED對象後面的對象都整體向前移動
if (val != DELETED) {
if (i != o) {
keys[o] = keys[i];
values[o] = val;
values[i] = null;
}
o++;
}
}
mGarbage = false;
mSize = o;//更新數組壓縮後的大小
}
//將一個<key,value>對放入到數組中
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);//二分查找key值對應的索引
if (i >= 0) {
//1.如果索引值大於0,說明數組已經存在該key了,直接更新key對應的value值
mValues[i] = value;
} else {
i = ~i;//沒有找到對應的索引,說明該<key,value>是新插入的,
//2.如果索引i小於數組的大小,並且該索引i對應value是DELETED對象,說明該key對應的對象被移除過,現在可以複用該key,並且更新對應的value對象。
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);
}
//3.將key和value值分別插入key數組和value數組
mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
mSize++;
}
}
// 返回數組的實際大小
public int size() {
if (mGarbage) {
gc();
}
return mSize;
}
//返回指定索引i對於的key值
public int keyAt(int index) {
if (mGarbage) {
gc();
}
return mKeys[index];
}
//返回指定索引對於的value對象
public E valueAt(int index) {
if (mGarbage) {
gc();
}
return (E) mValues[index];
}
//在指定的索引i上,設置value值
public void setValueAt(int index, E value) {
if (mGarbage) {
gc();
}
mValues[index] = value;
}
//返回指定key值對應的索引i,通過二分查找返回對於的索引
public int indexOfKey(int key) {
if (mGarbage) {
gc();
}
return ContainerHelpers.binarySearch(mKeys, mSize, key);
}
//返回指定value對象對應的索引i,通過線性查找
public int indexOfValue(E value) {
if (mGarbage) {
gc();
}
for (int i = 0; i < mSize; i++)
if (mValues[i] == value)
return i;
return -1;
}
//從SparseArray數組中清除key-value映射對
public void clear() {
int n = mSize;
Object[] values = mValues;
for (int i = 0; i < n; i++) {
values[i] = null;
}
mSize = 0;
mGarbage = false;
}
//將一個<key,value>對添加到數組的末尾
public void append(int key, E value) {
//1.key值小於最大的值,不能添加到數組的末尾,需要用put的方法將<key,value>存入
if (mSize != 0 && key <= mKeys[mSize - 1]) {
put(key, value);
return;
}
//2.如果數組容量不夠,需要先壓縮數組,回收被刪除的對象。
if (mGarbage && mSize >= mKeys.length) {
gc();
}
//3.將<key,value>添加到數組的末尾
mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
mValues = GrowingArrayUtils.append(mValues, mSize, value);
mSize++;
}