深入分析ArrayMap

来源:互联网 发布:mysql limit与where 编辑:程序博客网 时间:2024/06/07 15:08

前面我们分析了Android为了节省内存提供的一个HahMap<Integer, ?>的替代品SparseArray。SparseArray只能替代key的类型为int的Map。Android也提供了一个key不用局限于int的Map的实现,ArrayMap。老规矩我们通过调试来深入的分析一下ArrayMap(看本文章需要知道SparseArray的原理,可以参考我前面写的深入分析SparseArray文章)。

Android为了老版本也能使用ArrayMap,在support v4也提供了一份。和android.util.ArrayMap不同的是,android.support.v4.util.ArrayMap的put和get方法是由它的父类SimpleArrayMap实现的。它用来存放key和value的那些成员变量也声明在SimpleArrayMap里面,并且可见性是同一个包范围内可见。



所以为了调试的时候能从调试面板里面看到那些我们要分析的成员变量,我们要声明一个SimpleArrayMap来使用它的那些我们接下来要分析的put和get方法。



当我们执行到断点处的时候观察它的成员变量的值的变化,其中mHashes数组有两个不等于0的值,mArrays则为4个



我们在这大胆猜测mHashes里面存放的是我们put进去的两对key value的key的hash运算的值。而key value则都放到mArray里面,奇数位放置的是key,后面紧接着是它对应的key。还发现他们的顺序并不是我们put的时候的顺序。看来ArrayMap也是和SparseArray一样,SparseArray是通过对key排序(因为SparseArray的key必须为整型),而因为ArrayMap对key没有限制,它通过对key的hash之后的整型来进行排序,进而确定key value在mArrays上的位置(这里因为key value都放置在mArrays上,如果key的hash值在mHashes上的索引是i,在mArrays上对应的key value应该是2 * i, 2 * i + 1)。


上面我们进行了大胆的假设,下面我们来通过调试一步一步小心求证。我们进入到put方法。



indexOf这个方法看起来是找到我们put进来的key value应该放置在哪里,进去看看。


第69行的binarySearch我们在分析SparseArray的时候详细的分析过,这个函数的作用是在mHashes数组上用二分查找找到hash的index。如果查找成功则返回的是hash在mHashes数组上的index。如果查找失败,返回的是第一个比hash大的那个数的index并且按位取反(取反后是个负数,为了区分是查找成功还是失败,并且再次取反后还能得到插入hash的位置)。如果<0肯定是不存在这个key,直接返回进行移动插入操作将这对key value put进来。


如果查找公共index是个整数,从77行的代码看出他要通过index * 2在mArray数组上找到这个hash对应的key并比较传进来的key是否是equals(熟悉HashMap的都知道,key的hash值相等并不等于这两个key是同一个,equals相等才表示key是同一个key,如果不同的key的hash相等通过拉链法解决)。如果equals为true,这表示mArray[index * 2]就是我要要put的key,返回这个index进行更新value的操作。


83-90行代码是于index为中心点在mHashes上向左右遍历那些不同key值的hash相等的情况,并且通过比较key的equals找到相等的key,如果最终都没找到,就在我们找到的那个hash值相等的后面插入这个key value(通过放在冲突值的后面来解决冲突,不像HashMap的拉链法)。



383-388表示我们put的key已经存在,就将value设置给mArray[index * 2 + 1]覆盖老的值。如果<0表示,再次对index取反得到这对key value将要放置的地方。391-408 表示容量不够进行扩容。410-415表示要进行put的key value将插在有效数值的中间,所以通过将以前的数据进行移动空出mHashes[index],mArray[index * 2],mArray[index * 2 + 1],将我们要put的key value放入到mArray[index * 2],mArray[index * 2 + 1],当然还有把key的hash值放置到mHashes[index]中(代码417-420)。



看完put,我们来看看get。前面通过分析put的过程已经知道put的过程中会维持key的hash值们在mHashes数组上的非降序排列(mHashes[i] <= mHashes[i + 1])。232行的indexOfKey我们在put的分析中已经分析过会通过在mHashes上进行二分查找找到对应的key的hash所在的index,通过左右遍历在有冲突的hash值中找到真正相等的key的hash的index。>= 0表示找到了这个key,通过索引的对应关系返回key对应的value。< 0表示不存在这个key,返回null。

0 0
原创粉丝点击