SparseArray 理解

一、介绍

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 的数组。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值