深入分析SparseArray

曾几何时在写Android项目代码时,使用HashMap<Integer, ?>时IDE会给个建议推荐使用更加节省内存的SparseArray类,网上很多文章关于SparseArray的解释都提到了通过压缩去掉没用的数据的稀疏矩阵来节省空间。我很好奇这样怎么能通过key找到它对应的value呢。最近决定通过调试的方式来分析一下它的工作原理。


打开SparseArray的源码发现他有两个数组类型的成员变量,通过名字和类型猜测他们分别为了放置key和value。



既然是Map的替代品,那么首先得有put方法,首先我们先来看看它的源码。



当我们执行两次put方法后观察它的那两个成员变量的值的变化,



让我们调试分析put方法,首先它会进行一个二分查找


进入这个方法仔细分析。


从名字可以看出这是个二分查找。参数依次分别是存放key的数组,当前SparseArray中的item的数目,当前是2。最后一个参数是我们put时候的key。从源码可以看出进行了一个二分查找。这一次二分查找的过程如下图


这次二分查找并没有在mKeys的数组里面找到这次的key,从代码看出查找失败它会返回~lo(lo值的按位取反,因为符号位取反,正数就会变成负数,因此查找失败就会返回一个负数)。再看看调试运行的最后结果。


回到put函数这里


继续执行代码会进入到


这句代码,这句代码的作用就是把mKeys里面比key大的值都往后移动,空出mKeys的index位置,将key赋值给mKeys[index]。这样就让mKeys成为了一个升序排序的int数组。(这个函数里面还包含了mKeys容量已经满时的扩容,可以自己研究),什么都不说了,直接上图



最后在mValues数组上进行同样的操作,使mValues的index上的值为key对应的value值。这样就让key value在mKeys和mValues这两个数组上通过同样的index联系起来了。继续上图


执行完这次put方法后让我们再来看看mKeys和mValues的值的变化


我们可以看到mKeys还是按照升序排序,并且mKeys和mValues上同一个索引上的数值是一对对应的key value。

这里再补充说明如果put的key比mKeys里面的元素都大,直接在mKeys的后面append一个数据,不需要移动数据了。总结下来就是,put的时候会通过二分查找的方法找到比key都大的数据的分界点,大的都往后挪,再把key放到它该放的地方,保证mKeys的升序。mValues进行一样的位置的数据移动保证和对应key的索引值一样,使它们相关联起来。



分析完了put的过程,我们接着来分析get的过程。首先看源码



从源码可以看出首先也是对mKeys进行二分查找。前面已经知道如果找到返回的结果为正数,就是key在mKeys数组里面的索引,拿到这个索引就可以从mValues里面拿到对应的value。如果是负数说明这个key是没有value对应的。返回一个没有找到时的默认值,这里面是null。



总结一下,put的过程是一个对key的排序的过程,通过二分查找找到key排序后应该所在的索引,移动原有数据再把新put进来的key插入进来使mKeys保持它的升序,mValues进行同样的数据操作,保证对应的key value在两个数组中的索引一致。


通过分析源码,如果我们put的数据的key是个降序的过程每次都要进行移动数据排序。get的时候会在mKeys上进行二分查找找到key的index进而去mValues数组找到对应的value,看来SparseArray在性能上不会比HashMap好。

SparseArray的mKeys和mValues两个数组是从0到mSize充满了数据的数组,并不像HashMap那样通过hash来算出index来散列的存放数据,空间利用率并不高。因此SparseArray比HashMap在内存上还是有很大的优势的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值