Android ArrayMap和SparseArray系列存储对象分析

本文分析了Android中的ArrayMap和SparseArray系列,包括它们的特点、优缺点和使用场景。ArrayMap适用于存储各类数据,而SparseArray系列(如SparseBooleanArray、SparseIntArray、SparseLongArray)则针对特定数据类型。这些数据结构通过有序数组和二分查找提高效率,但不适合大量数据存储,且速度相对较慢。在内存性能方面,它们在存储少量数据时优于HashMap。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android为了提高开发效率,提供了一些了Sparse类用于取代Java原生的Map,主要是包括ArrayMap、SparseArray、SparseBooleanArray、SparseIntArray、SparseLongArray

ArrayMap

特点

1、hash值和键值对都是使用数组进行存储,有序数组
2、查找使用二分查找
3、只有ArrayMap可以用于存储各类数据,也就是键和值都可以自定义类型,其他的Sparse系列中键只能存储int类型的数据,SparseArray值可以存储各种类型,SparseBooleanArray、SparseIntArray、SparseLongArray值只能存储特定类型的数据

数据结构:
在这里插入图片描述
所以初始化的时候,mArray的大小就是mHashes的两倍,每次存储的时候,先二分查找hash值的位置,查找时候也会查找key是否存在,存在就返回存在的位置,否则就查找该放的位置。查找到hash值位置好之后,就会确定key的位置,因为key的位置都是hash位置的2倍大小位置,例如hash在4,对应的key就在8,value就在9。

优点:

1、代替HashMap,优点是数据结构不依赖与额外的结构体,存储结构是数组数据结构
2、当存储几百的数据时,内存性能消耗少于50%

缺点:

1、不能用于存储大量的数据
2、速度比hashmap慢,因为查找要求二分查找,添加删除要求在数组中插入和删除,要移动数组

使用详解:

 ArrayMap<String, Integer> map = new ArrayMap<>();
map.put("123",123);
Integer integer = map.get("124");
Integer remove = map.remove("123");

SparseArray:

特点

1、有序数组
2、查找使用二分查找
3、只有SparseArray可以用于存储各类数据,包括自定义实体类的对象,其他三个只能用于存储特定类型的数据

优点:

1、代替HashMap,优点是避免自动装箱、数据结构不依赖与额外的结构体,存储结构是数组数据结构
2、当存储几百的数据时,内存性能消耗少于50%
3、提高性能做了一个优化:删除键的时候,不立即删除,保留条目,标记为已删除。然后这个条目可以给相同键值的数据使用,或者将所有删除的条目集中进行删除。就是在数组扩展、检索数组时,执行垃圾回收。

缺点:

1、不能用于存储大量的数据
2、速度比hashmap慢,因为查找要求二分查找,添加删除要求在数组中插入和删除,要移动数组

使用讲解:

创建对象、添加、删除、遍历

SparseArray<String> array = new SparseArray<>();
array.append(0,"zero");
array.append(1,"fir");
array.append(2,"sec");

array.removeAt(0);

array.put(0,"zero1");
for (int i = 0; i < array.size(); i++) {
    Log.e("SparseArray","key="+array.keyAt(i)+":::::value="+array.get(array.keyAt(i)));
}

对象说明:

private static final Object DELETED = new Object();//values被删除时候,会标记为该对象,之后回收的时候,会将这一对数据删除
private boolean mGarbage = false; //标记是否要回收数组成员数据
private int[] mKeys; //存储key值的数组,默认不分配内存
private Object[] mValues; //存储values的数组,默认不分配内存
private int mSize; //整个sparsearray大小

方法分析:

创建对象:如果默认不传参的话,默认输入10,如果没有values的时候,只会创建keys的数组,不会创建values的值。如果传参是0的时候,初始化时候使用轻量级数组,不分配额外的内存

public SparseArray() {
    this(10);
}
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;
}

添加数据:如果插入的位置在之前存在了,就调用put方法,如果超出了,就调用gc方法,回收之前删除的数据位置;如果超出之前的大小了,就调用GrowingArrayUtils.append方法,将原来数组加1,存储后来的数据

public void append(int key, E value) {
    if (mSize != 0 && key <= mKeys[mSize - 1]) {
        put(key, value);
        return;
    }

    if (mGarbage && mSize >= mKeys.length) {
        gc();
    }

    mKeys = GrowingArrayUtils.append(mKeys, mSize, key);
    mValues = GrowingArrayUtils.append(mValues, mSize, value);
    mSize++;
}

GrowingArrayUtils类中的数组增长的方法

public static <T> T[] append(T[] array, int currentSize, T element) {
    assert currentSize <= array.length;

    if (currentSize + 1 > array.length) {
        T[] newArray = (T[]) Array.newInstance(array.getClass().getComponentType(),
                growSize(currentSize));
        System.arraycopy(array, 0, newArray, 0, currentSize);
        array = newArray;
    }
    array[currentSize] = element;
    return array;
}

put方法:先用二分查找法查找key是否存储过,如果存储过,直接修改value值即可。未找到情况下,如果key存在,values是被标记删除的,那么就会重新赋值,回归数组;都没有,进行数组回收;然后查找key应该放在的位置,将key和value插入到数组中。

public void put(int key, E value) {
    int i = ContainerHelpers.binarySearch(mKeys, mSize, key);

    if (i >= 0) {
        mValues[i] = value;
    } else {
        i = ~i; //i=0

        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);
        }

        mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
        mValues = GrowingArrayUtils.insert(mValues, mSize, i, value);
        mSize++;
    }
}

删除:就是将key对应的value值设置为标识DELETED,并且mGarbage为true,标记可以进行回收了

public void removeAt(int index) {
    if (index >= mSize && UtilConfig.sThrowExceptionForUpperArrayOutOfBounds) {
        // The array might be slightly bigger than mSize, in which case, indexing won't fail.
        // Check if exception should be thrown outside of the critical path.
        throw new ArrayIndexOutOfBoundsException(index);
    }
    if (mValues[index] != DELETED) {
        mValues[index] = DELETED;
        mGarbage = true;
    }
}

其他方法:

clone(): 克隆
get(int key):根据key查找value
get(int key,E valueIfKeyNotFound):根据key查找value,给了一个默认值
delete(int key):删除key对应的value
removeReturnOld(int key):返回之前删除的值
remove(int key):删除value值
removeAt(int index):删除index位置的数据
removeAtRange(int index,int size):删除范围内的数据,从index开始到index+size-1
gc():回收,将之前删除的数据回收去除
size():先回收,然后返回数组大小
keyAt(int index):index位置的key值
valueAt(int index):根据位置查找对应的value值
setValueAt(int index,E value):设置索引位置的value值
indexOfKey(int key):根据key查找mKeys数组的位置
indexOfValue(E value):根据value查找在mValues数组的位置,使用==判断,使用二分查找法
indexOfValueByValue(E value):使用equals判断等价
clear():清空数组
append(int key,E value):
toString():
DELETED:对象被删除之后,value被标记为这个

SparseBooleanArray

内容基本和SparseArray一样的,只是存储的value是boolean值
使用:

SparseBooleanArray array = new SparseBooleanArray();
        array.append(0,true);
        array.put(1,false);
        array.append(2,true);
        array.put(5,false);
//        array.removeAt(3);
        array.delete(2);

        for (int i = 0; i < array.size(); i++) {
            Log.e("SparseBooleanArray","key="+array.keyAt(i)+":::::value="+array.get(array.keyAt(i)));
        }

SparseIntArray

使用:

SparseIntArray array = new SparseIntArray();
        array.append(0,34);
        array.put(1,23);
        array.append(2,58);
        array.put(5,67);
//        array.removeAt(3);
        array.delete(2);

        for (int i = 0; i < array.size(); i++) {
            Log.e("SparseIntArray","key="+array.keyAt(i)+":::::value="+array.get(array.keyAt(i)));
        }

SparseLongArray:

使用:

SparseLongArray array = new SparseLongArray();
        array.append(0,34356L);
        array.put(1,23789L);
        array.append(2,58123456);
        array.put(5,67);
//        array.removeAt(3);
        array.delete(2);

        for (int i = 0; i < array.size(); i++) {
            Log.e("SparseLongArray","key="+array.keyAt(i)+":::::value="+array.get(array.keyAt(i)));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值