一、介绍
SparseArray(稀疏数组) ; Android内部特有的api ; SparseArray更节省内存空间;
android 提供的数据结构, 功能类似HashMap ; 与map不同的是key 只能是int ;
二、使用
SparseArray<Object> sparseArray = new SparseArray<>(0);
sparseArray.put(0,null);
sparseArray.put(1,"abc1");
sparseArray.put(2,new String("abcab2"));
sparseArray.put(3,3);
sparseArray.put(4,new Boolean(true));
sparseArray.put(5,new Object());
sparseArray.put(8,new String("82abc8"));
sparseArray.put(20,"abcbc20");
sparseArray.put(0,"a0");
int size = sparseArray.size();
for (int i = 0;i < size;i++) {
Log.e(TAG, "sparseArraySample: i = " + i + ";value = " + sparseArray.get(sparseArray.keyAt(i)) );
}
三、代码分析
3.1 成员变量
3.2 构造方法
默认初始化容量为 10 ; 可以看到当 initialCapacity 为 0 时,mKeys 和 mValues 为空数组; 否则 mValues 通过 ArrayUtils#newUnpaddedObjectArray 方法获得一个最小容量为 initialCapacity 的数组;
那为什么不直接new 数组,而是调用newUnpaddedObjectArray 方法呢?这里涉及一个概念下面我们再来看一下;
3.3 get 方法
先通过二分查找找到下标,然后如果如果没有被打上DELETED 标记,能从数据取出,则找到,否则为未找到;有DELETED 标记,代表已被删,回头在gc 的时候会被清理掉;先二分查找,所以查找性能不如HashMap 的直接索引。
3.4 delete 方法
先二分查找,找到就打标记DELETED ,而没有直接删;更改mGarbage ;删除将会涉及到数组元素的移动,所以只是先标记,然后统一删一次;
3.5 SparseArray 的gc 方法
这个gc 指的是SparseArray 自己的那个方法;gc 意味着整理(数组的移动,有效容量的重新赋值);
将打上DELETED 标记的元素移除,再整理移动元素到前面,再更新mSize 的;
3.6 put 方法
3.7 append 方法
append 是对put 的扩展, 如果场景是在末尾追加的话,推荐用该方法;
在有些场景该方法会省去二分查找,直接在末尾添加。
四、SparseArray 与HashMap 对比
相比HashMap ,SparseArray 会更节省内存,由于使用二分查找,速度上会有劣势,但综合 SparseArray 避免装箱拆箱,相同数据量扩容次数少的优势,又使其在速度上扳回一局,具体情况我们来看数据对比。
100000 条数据,可见取数据HashMap 要快一点点(从这组数据来看1.8ms);内存占用SparseArray 要节省很多;
五、内存对齐概念
接下来看一下上面提到的newUnpaddedObjectArray 方法;
5.1 newUnpaddedObjectArray 方法
返回至少为minLength,但可能更大的数组。 增加的大小来自避免在数组之后进行任何填充。 填充量取决于componentType和内存分配器实现而变化,这里就涉及了一个内存对齐的概念。
Java数据类型在内存中使用不同的大小。 如果仅分配所需的容量,则在下一 次内存分配之前,末端的一些空间将不使用,此空间称为填充。 因此,为了 不浪费此空间,将数组做大一点。
5.2 什么是内存对齐
还是用一个例子带出这个问题,看下面的小程序,理论上,32位系统下,int占4byte,char占一个byte,那么将它们放到一个结构体中应该占4+1=5byte;但是实际上,通过运行程序得到的结果是8 byte,这就是内存对齐所导致的。
5.3 为什么要进行内存对齐
尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的。它一般会以双字节,四字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度。
所以传进去的是11 ,内存图如下(紫色是11 的数组长度所占的空间,蓝色是差一个到80 字节的内存),那么newUnpaddedObjectArray 方法会返回长度为12 的数组。