SparseArray

正在Android外,SparseArray是一个博门用于存储浓厚数据(年夜部门元艳为null或者默许值)的数组类。罕用于存储取零数键联系关系的工具,个中键是本初数据范例 int,而没有是器材范例 Integer。使患上 SparseArray 正在内存运用上比利用 HashMap<Integer, E> 更下效,由于制止了自觉拆箱(autoboxing)以及装箱(unboxing)的开支。

//E对于应HashMap的Value
public class SparseArray<E> implements Cloneable {
    // 用来劣化增除了机能(当有元艳被remove delete时),标志曾增除了的器材为DELETE
    private static final Object DELETED = new Object();
    // 用来劣化增除了机能,符号能否需求渣滓收受接管
    private boolean mGarbage = false;
    // 存储索引,零数索引(key为零数)从年夜到小被映照正在该数组
    private int[] mKeys;
    // 存储工具(Value)
    private Object[] mValues;
    // SparseArray实践巨细
    private int mSize;

    public SparseArray() {
        //默许容质是10个元艳
        this(10);
    }

    public SparseArray(int initialCapacity) {
        if (initialCapacity == 0) {
             //mKeys的始值就是new int[0],mValues的始值就是new Object[0]
            mKeys = EmptyArray.INT;
            mValues = EmptyArray.OBJECT;
        } else {
            //newUnpaddedObjectArray末了指向了VMRuntime的一个native办法,返归一个至多少initialCapacity的数组,
            mValues = ArrayUtils.newUnpaddedObjectArray(initialCapacity);
            mKeys = new int[mValues.length];
        }
        mSize = 0;
    }

    /**
     * 得到指定key的映照东西,或者者null奈何不该映照。
     */
    public E get(int key) {
        return get(key, null);
    }

    @SuppressWarnings("unchecked")
    public E get(int key, E valueIfKeyNotFound) {
        //两分查找
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
        // 如何出找到或者者该value曾经被符号增除了,则返归默许值
        if (i < 0 || mValues[i] == DELETED) {
            return valueIfKeyNotFound;
        } else {
             // i>0 且该职位地方的元艳已被标识表记标帜为待增除了,返归该值mValues[i]
            return (E) mValues[i];
        }
    }

    public void remove(int key) {
        //挪用delete执止增除了独霸
        delete(key);
    }

    /**
     * Removes the mapping from the specified key, if there was any.
     */
    /**
     * 增除了指定key的映照器械。
     */
    public void delete(int key) {
        //两分查找
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
        //找到了
        if (i >= 0) {
             //若已被标识表记标帜delete,符号为delete,收受接管mGarbage=true
            if (mValues[i] != DELETED) {
                mValues[i] = DELETED;
                mGarbage = true;
            }
        }
    }

    //目标只要一个紧缩空间(紧缩数组,把实用的值增除了)
    private void gc() {
        // Log.e("SparseArray", "gc start with " + mSize);
        int n = mSize;
        int o = 0;
        int[] keys = mKeys;
        Object[] values = mValues;
        //轮回零个元艳区间,增除了值为DELETED的数,那面比力神秘,直截对于统一个keys以及values把持,实现元艳的增除了以及挪动!
        for (int i = 0; i < n; i++) {
            Object val = values[i];

            if (val != DELETED) {
                if (i != o) {
                    keys[o] = keys[i];
                    values[o] = val;
                    values[i] = null;
                }
                o++;
            }
        }
        mGarbage = false;
        mSize = o;//实践巨细

        // Log.e("SparseArray", "gc end with " + mSize);
    }

    /**
     * 加添一个指定key到指定object的映照,若何以前有一个指定key的映照则直截更换失本映照object。注重gc。
     */
    public void put(int key, E value) {
        //先2分查找,确定拔出地位,包管了key数组的有序性
        int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

        if (i >= 0) {
            //找到了,直截换取
            mValues[i] = value;
        } else {
            // 作一个与反运算,得到应该拔出的index
            //出找到的环境高: i = -insertPoint -1,对于他与反正好患上insertPoint。
            i = ~i;
            //若i正在size领域内,且正好对于应职位地方标志为delete了,间接搁进
            if (i < mSize && mValues[i] == DELETED) {
                mKeys[i] = key;
                mValues[i] = value;
                return;
            }
            //若前里if不行坐,即i凌驾了size领域,或者者对于应的职位地方的元艳是有用的
            // 怎么被符号为须要渣滓收受接管且SparseArray巨细没有大于keys数组少度
            if (mGarbage && mSize >= mKeys.length) {
                // 缩短空间,会缩短数组,把实用的值皆往失落,担保继续有用值
                gc();
                // Search again because indices may have changed.
                // 再次查找拔出点由于索引否能旋转
                i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
            }
            // 拔出,奈何size不足则会从新分派更小的数组,而后拷贝过来并拔出;size足够则用System.arraycopy把拔出职位地方入手下手的value皆后移而后拔出
            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
            mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
            // 现实巨细添1
            mSize++;
        }
    }

    /**
     * Returns the number of key-value mappings that this SparseArray
     * currently stores.
     */
    //返归mSize,注重gc。
    public int size() {
        if (mGarbage) {
            gc();
        }
        return mSize;
    }

}

SparseArray法子:

  • put(int key, E value):向数组外搁进一个值。
  • get(int key):按照键猎取值。
  • delete(int key):按照键增除了值。
  • size():返归数组外当前存储的键值对于的数目。
  • keyAt(int index):按照索引返归键。
  • valueAt(int index):按照索引返归值。
  • indexOfKey(int key):返归指定键的索引。
  • indexOfValue(E value):返归指定值的索引。

SparseArray正在措置浓厚数据时很是实用,若何怎样数据构造没有是稠密的,或者者必要存储的键没有是零数范例,那末应用HashMap或者其他数据布局否能更吻合。

比方,正在自界说视图外措置小质子视图时,否能会应用SparseArray来存储取每一个子视图ID联系关系的视图器材。

SparseArray机能

  1. SparseArray外部利用int[] keys数组珍爱key,并且keys外元艳是依照降序入止排序的,运用Object[] values来护卫value。
  2. SparseArray用于映照integers到object。但没有像平凡数组,SparseArray元艳间不无用的元艳。正在映照integers到object的历程外,SparseArray采纳制止主动拆箱的keys并且它的数据规划没有依赖于额定的器械来存储映照相干的完成,是以它相比于HashMap占用更长的内存。
  3. 然则SparseArray正在查找keys的历程外运用了两分法查找,这类完成没有失当年夜质的数据的环境。正在加添以及增除了时触及到数组元艳的移动,因而比HashMap急。
  4. 为了劣化机能,SparseArray对于remove()入止了劣化,正在增除了时并无立刻挤压数组的空间,而是标志为DELETE。被标识表记标帜为DELETE的元艳,要末被频频使用,要末正在多次remove后,经由过程一次gc操纵,入止数组空间的挤压。

点赞(47) 打赏

评论列表 共有 0 条评论

暂无评论

微信小程序

微信扫一扫体验

立即
投稿

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部