深入分析ArrayMap

article/2025/3/4 13:49:59

前面我们分析了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。


http://chatgpt.dhexx.cn/article/MWG0XQqW.shtml

相关文章

ArrayMAP介绍

它不是一个适应大数据的数据结构&#xff0c;相比传统的HashMap速度要慢&#xff0c;因为查找方法是二分法&#xff0c;并且当你删除或者添加数据时&#xff0c;会对空间重新调整&#xff0c;在使用大量数据时&#xff0c;效率并不明显&#xff0c;低于50%。 ArrayMap is a ge…

Android特别的数据结构(二)ArrayMap源码解析

1. 数据结构 public final class ArrayMap<K,V> implements Map<K,V> 由两个数组组成&#xff0c;一个int[] mHashes用来存放Key的hash值&#xff0c;一个Object[] mArrays用来连续存放成对的Key和ValuemHashes数组按非严格升序排列初始默认容量为0减容&#xff…

ArrayMap 源码的详细解析

最近在写framework层的系统服务&#xff0c;发现Android 12中用来去重注册监听的map都是用的ArrayMap&#xff0c;因此仔细研究了ArrayMap的原理。 目录 一. ArrayMap概述 二. ArrayMap源码解析 1.主要包含的成员变量 2.构造函数 3. public boolean containsKey(Object ke…

SparseArray和ArrayMap

首先我们来介绍一下HashMap&#xff0c;了解它的优缺点&#xff0c;然后再对比一下其他的数据结构以及为什么要替代它。 HashMap HashMap是由数组单向链表的方式组成的&#xff0c;初始大小是16&#xff08;2的4次方&#xff09;&#xff0c;首次put的时候&#xff0c;才会真…

SparseArray与ArrayMap

SparseArray SparseArray核心代码 两个构造函数默认数组容量10 public SparseArray() {this(10); } public SparseArray(int initialCapacity) {if (initialCapacity 0) {mKeys EmptyArray.INT;mValues EmptyArray.OBJECT;} else {mValues ArrayUtils.newUnpaddedObjectA…

arraymap android,深入剖析 Android中的 ArrayMap

数据集合在任何一门编程语言中都是很重要的一部分&#xff0c;在 Android 开发中&#xff0c;我们会实用到ArrayList, LinkedList, HashMap等。其中HashMap是用来处理键值对需求的常用集合。 而Android中引入了一个新的集合&#xff0c;叫做ArrayMap&#xff0c;为键值对存储需…

ArrayMap 笔记整理

源码基于 API 25 主要参考文章&#xff1a;面试必备&#xff1a;ArrayMap源码解析 1、概述 截图自&#xff1a;面试必备&#xff1a;ArrayMap源码解析 在开始讲解源码之前&#xff0c;需要说明 ArrayMap 的底层实现结构&#xff0c;即两个数组&#xff1a; int[] mHashes; /…

ArrayMap 原理

一 概述 在移动设备端&#xff0c;内存资源很珍贵&#xff0c;HashMap 为实现快速查询带来了很大内存的浪费。为此&#xff0c;2013年5月20日 Google 工程师 Dianne Hackborn 在 Android 系统源码中新增 ArrayMap 类&#xff0c;从 Android 源码中发现有不少提交&#xff0c;专…

不再害怕面试问ArrayMap一文完全看懂Android ArrayMap源码解析

作者&#xff1a;VIjolie 前言 ArrayMap是谷歌推出的在安卓等设备上用于替代HashMap的数据结构&#xff0c;和HashMap相比&#xff0c;具有更高的内存使用率&#xff0c;因此适合在Android等内存较为紧张的移动设备&#xff0c;下面结合源码分析ArrayMap实现原理&#xff0c;主…

ArrayMap原理解析

1.ArrayMap是什么 一个通用的key-value映射数据结构 相比HashMap会占用更少的内存空间 android.util和android.support.v4.util都包含对应的ArrayMap类 2.为什么要使用ArrayMap ArrayMap是一个普通的键值映射的数据结构&#xff0c;这种数据结构比传统的HashMap有着更好的内…

ArrayMap源码解析

一、数据结构 ArrayMap是一个key-value的数据结构&#xff0c;它比HashMap有更高的内存效率 它映射到两个数组结构&#xff1a;一个整数数组mHashes&#xff0c;用来保存key的hashcode&#xff1b;一个对象数组mArray&#xff0c;保存key-value 它不适用于大量数据的存储&…

ArrayMap的使用与详解

数据集合在任何一门编程语言中都是很重要的一部分&#xff0c;在 Android 开发中&#xff0c;我们会实用到List,ArrayList, HashMap等。List和ArrayList配合使用&#xff0c;其中HashMap是用来处理键值对需求的常用集合。 而Android中引入了一个新的集合&#xff0c;叫做ArrayM…

ipdb 调试 - 终端显示正常,日志显示乱码

问题描述 ipdb调试模型&#xff0c;在 vscode 终端正常显示&#xff0c;但日志文件中&#xff0c;输入流将ipdb调试信息的颜色代码记录在文件中&#xff0c;日志文件无法查阅。 解决方案&#xff1a; 提示&#xff1a;修改ipdb的终端颜色属性 点击 ipdb&#xff0c;进入 ipdb …

ipdb调试dataloader

ipdb不可以直接放入__init__/__len__/__getitem__进行调试 需要在主函数中中断调试&#xff0c;例如colab中&#xff1a; 输入需要查询的变量即可

初次使用python(2)之如何下载ipdb模块

上次提到了ipdb这个python中用于进行调试的模块&#xff0c;但在python中是额外的package。所以&#xff0c;这篇文章写得是如何下载ipdb模块。 在Windows环境中&#xff0c;需要用pip来下载所有模块。 1.安装pip 我们仍需要在python官网上找到pip文件&#xff0c;下载地址是&a…

python ipdb 调试代码

python ipdb 调试代码 安装 pip install ipdb使用 第一种方法 python -m ipdb xxx.py #单步调试也可以写一个.py文件&#xff0c;如下&#xff0c;来执行。 import os os.system(python -m ipdb xxx.py)第二种方法 在需要断点的地方插入两句话 from ipdb import set_tra…

python debug ipdb

pudb使用 to be continued… ipdb和pdb区别 实际上ipdb是pdb的扩展版本&#xff0c;在pdb的基础上添加了如下功能&#xff1a; 可以使用tab&#xff08;提示&#xff09;补全代码的功能&#xff08;我觉得这一点上我就完全倒戈了…&#xff09;调试不再是黑白的&#xff0c…

Python调试pdb和ipdb

什么是pdb和ipdb 不知道大家在用Python写代码出现报错时是怎样调试的&#xff0c;从报错提示定位回去一步一步check每一行&#xff1f;如果没有IDE或者命令行写代码时又该怎样快速调试&#xff1f;这时如果使用pdb进行调试将会异常方便。 Pdb就是Python debugger&#xff0c;…

python调试模块ipdb

1. 调试python ipdb是用来python中用以交互式debug的模块&#xff0c;可以直接利用pip安装; 其功能类似于pycharm中 python控制台&#xff0c; 而使用ipdb 的优点&#xff0c;便是直接在代码中调试&#xff0c; 避免了在python控制台&#xff0c;或者重新设置一些简单变量。…

python调试器 ipdb

文章目录 1. 介绍1.1 常用调试方式1.2 安装 ipdb 2. 用法3. 命令3.1、查看源代码3.2、添加断点3.3 添加临时断点3.4 清除断点3.5、打印变量值3.6、逐行调试命令3.7、非逐行调试命令3.8 跳出函数&#xff0c;跳入函数3.9、查看当前函数所有参数3.10 打印变量的值3.11、打印变量类…