SparseArray & ArrayMap

HashMap,ArrayMap,SparseArray 源码角度分析,Android中的数据结构你该如何去选择? 在get的时候,我们首先会根据我们的key去计算它的hash值,如果这个hash值不存在,我们直接反回null。如果存在,在没有发生hash冲突的情况下也就是根据当前hash值计算出的索引上的存储数据不是以树和链表的形式存储的时候,我们直接返回当前索引上存储的值,如果时链表树,我们就去遍历节点上的数据通过equals去比对,找到我们需要的在返回。通过上面我可以得出结论,当HashMap没有发生hash冲突时,hashMap的查找和插入的时间复杂度都是O(1),效率时非常高的。 阅读详情

SparseArray 和 ArrayMap 都是 Android 特有的集合类,出现在 android.util 包下。
它们的诞生原因是 Android 在内存和性能优化上的特殊需求 —— 在移动设备上,内存、GC 频率和性能都是敏感指标,所以 Google 给我们提供了比 Java 标准集合更轻量的替代方案。

它们在功能上与 Java 标准库中的 HashMap 类似,都是键值对(Key-Value)存储,但在内部实现上做了显著的改进。

一、SparseArray

SparseArray 是一种将整数映射到对象的键值对数据结构。它的设计初衷是为了替代 HashMap<Integer, Object>,特别是在键是连续或稀疏的整数时。

它在系统源码和三方库中很常见,但因没有去了解过它,以至于很长时间都不知道它是干什么用的,只知道看上去和 HashMap 很像。

特点:两个数组(key 升序排列,value 对应存储)

mKeys:   [  1,   3,   5  ]
mValues: ["A", "B", "C"]

查找流程:
1. 用二分查找 mKeys 找到 key 的位置
2. 用下标去 mValues 取值

结构示意:

┌──────────────┐     ┌──────────────┐
│ mKeys  int[] │     │ mValues Obj[]│
├─────┬────────┤     ├─────┬────────┤
│  0  │   1    │ --> │  0  │  "A"   │
│  1  │   3    │ --> │  1  │  "B"   │
│  2  │   5    │ --> │  2  │  "C"   │
└─────┴────────┘     └─────┴────────┘

删除元素时不会立刻移动数组,而是标记为“DELETED”占位符,等需要时再 gc() 进行压缩

二分查找大家都懂吧,就是那个过程很简单,细节是魔鬼的算法,简单介绍下,在给定一个有序的数据结构中去查找一个元素,通过目标元素的特征与中间的元素比较确定它属于哪半部分,往复循环,每次都是缩小目标数据结构的一半,直到找到元素,很好理解是不是,恩,保持你对它的第一印象就行了。

原理

SparseArray 内部使用两个并行的数组:一个用于存储键(int[] mKeys),另一个用于存储值(Object[] mValues)。当添加一个键值对时,它会根据键的大小将键插入到 mKeys 数组的正确位置,并同时将值插入到 mValues 数组的对应位置。由于数组是连续存储的,查找操作使用二分查找(binary search),其时间复杂度为 O(logn),而添加和删除操作可能需要移动数组元素,其时间复杂度为 O(n)。

作用与功能

SparseArray 避免了 HashMap 中每个键值对都需要创建一个 Entry 对象的开销。在 HashMap 中,每个 Entry 对象包含了键、值以及指向下一个 Entry 的引用,这些都会占用额外的内存。而 SparseArray 仅仅存储原始的 int 键和 Object 值,因此内存消耗更低。

Java 泛型不支持基本类型,Integer 会频繁装箱(int → Integer)和拆箱(Integer → int),增加 CPU 与内存占用。SparseArray就避免了频繁装箱/拆箱。

虽然添加和删除操作可能较慢,但对于查找操作,二分查找在数据量不大的情况下(通常在数百或数千个元素以内),其性能可以媲美甚至超过 HashMap。数据量大时,性能退化至少 50 %!

SparseArray 家族

SparseArray 只能存储 key 为 int 的数据,当我们要存储的数据 key 不为 int 类型或 value 是基本类型 怎么办?不慌,下面有请SparseArray 家族成员登场

  • SparseArray<E>
    Key = int,Value = Object,替代 HashMap<Integer, E>
  • SparseBooleanArray
    Key = int,Value = boolean,替代 HashMap<Integer, Boolean>
  • SparseIntArray
    Key = int,Value = int,替代 HashMap<Integer, Integer>
  • SparseLongArray
    Key = int,Value = long,替代 HashMap<Integer, Long>
  • LongSparseArray<E>
    Key = long,Value = Object,替代 HashMap<Long, E>

应用场景

  • 键为 int 类型:当你的键是整数时,这是首选。
  • 数据量相对较小:如果键值对的数量不多,SparseArray 的性能优势更为明显。
  • 键是稀疏的:即使键的数值范围很大,但实际使用的键数量不多,SparseArray 也能很好地工作。例如,你可能需要将视图 ID(如 R.id.my_view)映射到某个对象,这些 ID 是不连续的,但总数不多。

在安卓中常见的就是存储监听/订阅列表或存储 View 之类的。

缺点

  • 插入时会用二分查找 + 数组移动,数据量大时效率比 HashMap 低
  • 不是线程安全的
  • 删除操作延迟清理(gc() 机制)

如果只使用SparseArray 你就会发现,还是 HashMap 好用,因为SparseArray 没有像HashMap 那种以对象为 key 的存储方式,不要慌,接下来登场的是另一个安卓特有集合《ArrayMap》

二、ArrayMap

ArrayMap 是一种通用型的键值对数据结构,它的设计目的是为了在键值对数量较少时,替代 HashMap 以获得更高的内存效率和更好的性能。

特点:一个 int[] mHashes(存 hashCode,升序),一个 Object[] mArray(交错存储 key 和 value)

mHashes: [100, 200, 350]
mArray:  [ "key1", "val1", "key2", "val2", "key3", "val3" ]

结构示意:

┌────────────────┐      ┌────────────────────────────────┐
│ mHashes  int[] │      │ mArray Object[]                │
├─────┬──────────┤      ├─────┬─────────────┬─────┬──────┤
│  0  │  100     │ -->  │  0  │  "key1"     │  1  │"val1"│
│  1  │  200     │ -->  │  2  │  "key2"     │  3  │"val2"│
│  2  │  350     │ -->  │  4  │  "key3"     │  5  │"val3"│
└─────┴──────────┘      └─────┴─────────────┴─────┴──────┘

查找流程:

  1. 在 mHashes 用二分查找 hashCode
  2. 在 mArray 中取出对应的 key,调用 equals() 比较
  3. 如果 key 相等,返回对应的 value

查找下标的操作:

int indexOf(Object key, int hash) {
  	// 当前数据的大小
    final int N = mSize;

    // Important fast case: if nothing is in here, nothing to look for.
  	// 如果大小为0,说明没有数据存在,返回 -1 表示插入
    if (N == 0) {
        return ~0;
    }
		
  	// 二分查找到下标
    int index = binarySearchHashes(mHashes, N, hash);

    // If the hash code wasn't found, then we have no entry for this key.
  	// 返回要插入的下标位置
    if (index < 0) {
        return index;
    }

    // If the key at the returned index matches, that's what we want.
    // 如果返回索引处的键匹配,那就是我们想要的。index 是 0 的话,那么它的值就是1的位置。
    // index<<1 就等于 0 + 1
    if (key.equals(mArray[index<<1])) {
        return index;
    }

    // Search for a matching key after the index.
  	// 遇到冲突,开放地址发解决冲突,从前往后找
    int end;
    for (end = index + 1; end < N && mHashes[end] == hash; end++) {
        if (key.equals(mArray[end << 1])) return end;
    }

    // Search for a matching key before the index.
  	// 从后往前找
    for (int i = index - 1; i >= 0 && mHashes[i] == hash; i--) {
        if (key.equals(mArray[i << 1])) return i;
    }

    // Key not found -- return negative value indicating where a
    // new entry for this key should go.  We use the end of the
    // hash chain to reduce the number of array entries that will
    // need to be copied when inserting.
 		// 未找到是取反表示需要插入的位置
    return ~end;
}

原理

与 SparseArray 类似,ArrayMap 也是通过两个并行的数组来实现的:一个用于存储键的哈希码(int[] mHashes),另一个用于存储键值对(Object[] mArray)。mArray 数组中,键和值是交替存储的,即 mArray = {key1, value1, key2, value2, ...}。查找、添加和删除操作的实现也类似于 SparseArray,首先通过二分查找找到键的哈希码,然后检查键是否相等。

作用与功能

ArrayMap 同样避免了为每个键值对创建 Entry 对象的开销,从而大大减少了内存占用。对于少量键值对,ArrayMap 的内存消耗远低于 HashMap。

在数据量较小(通常在数百个元素以内)时,ArrayMap 的查找、添加和删除操作由于其精简的内部结构和对哈希冲突的优化处理,其性能可以优于 HashMap。它不需要处理复杂的链表或红黑树结构,代码实现更轻量。

应用场景

  • 键值对数量较少:ArrayMap 的性能拐点通常在数百个元素左右,当数据量超过这个范围,HashMap 的性能优势会逐渐显现。
  • 需要通用键值对存储:与 SparseArray 不同,ArrayMap 的键可以是任意对象,而不仅仅是 int 类型。
  • 性能和内存都是关键考虑因素:在内存受限的移动设备上,例如在一个 RecyclerView 的 Adapter 中存储少量的数据,ArrayMap 是一个很好的选择。

总的来说 ArrayMap 就是 替代 HashMap<K,V> 的轻量实现。

缺点

  • 插入/删除需要移动数组,数据量大时性能差
  • 不是线程安全的
  • 数据量大时性能不如 HashMap

三、总结

  • SparseArray 系列:Key 是原始数值类型(int、long),替代 HashMap<Integer, T>,避免装箱节省内存。
  • ArrayMap:Key 可以是任意对象,替代 HashMap<K,V>,小数据量节省内存。
  • 共同点:
    • 数据量少时比 HashMap 更省内存
    • 查找是二分法 + 数组结构
    • 插入删除需要移动数据,性能不适合超大数据集
Android中SparseArray性能优化的使用方法 主要为大家详细介绍了Android中SparseArray性能优化的使用方法,感兴趣的小伙伴们可以参考一下 立即下载

相关推荐

Qt+WebAssembly学习笔记(六)win10+Qt6.4.0rc1开发环境搭建

前言:因项目的缘故,笔者有段时间没测试了,官方也修复了很问题,笔者今天记录下最新版本环境搭建。

aggs1990的专栏 3765

深度解读ArrayMap优势与缺陷

ArrayMap经典文章:深度解读ArrayMap优势与缺陷;在移动设备端内存资源很珍贵,HashMap为实现快速查询带来了很大内存的浪费。为此,2013年5月20日Google工程师Dianne Hackborn在Android系统源码中新增ArrayMap类,从Android源码中发现有不少提交专门把之前使用HashMap的地方改用ArrayMap,不仅如此,大量的应用开发者中广为使用。然后,你是否研究过这么广泛使用的基础数据结构存在缺陷?要回答这个问题,需要...

许进进的博客 937

零中频接收机实战:DC Offset的5种常见解决方案与调试技巧

本文针对零中频接收机中DC Offset这一核心挑战,深入剖析了其产生机理与对信号解调的严重影响。文章从实战角度出发,系统性地介绍了五种解决方案,包括硬件预防、数字域校正、I/Q不平衡联合校正等,并分享了关键的实验室调试与产线测试技巧,旨在帮助射频工程师有效提升接收机性能。

weixin_29234509的博客 397

SparseArray 你不知道的东西

SparseBooleanArray的value为boolean类型,SparseIntArray的value为int类型,SparseLongArray的value为long类型。2.通过二分法来查询、添加、删除、更新数据。

编程语言开发、框架原理、编程思想、最佳实践技巧经验分享。致力于各种编程技术的技巧经验干货分享,讲解开发避坑技巧,追踪开发前沿技术,实战展开解决难题。 程序员小迷助您在编程路上越走越好! 851

【自动驾驶】汽车智能驾驶计算芯片

本文介绍汽车智能驾驶计算芯片的软硬件要求、 可靠性和安全性要求、 性能要求,和相应的试验方法。除了用于汽车智能驾驶, 其他领域的计算芯片可参照执行。

Mr.Cssust的博客 2631

CTF逆向实战:如何快速识别RC4、TEA和Base64的魔改变种?

本文针对CTF逆向比赛中常见的加密算法魔改问题,详细讲解了如何快速识别和破解RC4、TEA和Base64的变种。通过分析算法核心特征、常见魔改手法,并结合动态调试与脚本编写等实战技巧,帮助逆向分析人员有效应对算法混淆,提升解题效率。

agile9scrum的博客 782

LinkedList和ArrayList的区别

LinkedeList和ArrayList都实现了List接口,但是它们的工作原理却不一样。它们之间最主要的区别在于ArrayList是可改变大小的数组,而LinkedList是双向链接串列(doubly LinkedList)。ArrayList更受欢迎,很多场景下ArrayList比LinkedList更为适用。 LinkedList和ArrayList的区别 LinkedList和A

Bruce Lee的专栏 1135

Maestro 薛定谔软件简单分子对接案例

#参考:Maestro 薛定谔软件使用:Maestro 薛定谔对接:sid=287811。

weixin_42357472的博客 1万+

Android性能优化-代码优化和图片优化

此篇博客主要是参考《Android高级进阶》,关于Android开发过程性能优化中的代码优化和图片优化做一个记录。

小唯的博客 556

指纹浏览器指纹工厂(下):基于真实设备数据特征的马尔可夫链生成与校验

本文揭示了静态指纹生成算法在高级风控时序追踪下的致命缺陷,指出违背设备演进马尔可夫性质(如无状态跳跃、因果断裂)是导致指纹存活率骤降的核心原因。通过分析风控系统的时序状态机与多维特征验证机制,提出基于隐马尔可夫模型(HMM)的动态指纹架构:以真实设备的状态转移链为蓝本,构建异步演进的“数字基因熔炉”,通过非均匀时间步长、突发事件响应及微观因果绑定,模拟软硬件独立更新的物理法则。最终实现指纹在时间维度与微观特征上的自洽,规避风控的时序陷阱。

数据知道的博客 416

基于STM32L4XX、HAL库的AD7124-8BCPZ模数转换器ADC驱动程序设计

/ 公式: Voltage = (adc_value / (2^23 - 1)) * Vref。// 模式控制位[7:5]=000 (连续转换模式)// 3.2 配置通道0,使其使用AIN0(+)和AIN1(-),并关联到配置0和滤波器0。= 0x14) { // AD7124-8的ID是0x14。// 双极性操作,缓冲AINP/AINN。

zhusl6688的博客 376

菜鸟看源码之SparseArray

Android SparseArray 源码分析 SparseArray 将整数映射到对象。和普通的对象数组不一样,SparseArray的元素之间可以有间隙。和使用HashMap将整数映射成对象相比,SparseArray 效率更高(关于SparseArray 和HashMap的效率的对比,请看文末的参考链接2),因为SparseArray 避免的键的自动装箱,而且对于每个映射,SparseA

leilifengxingmw的博客 704

基于STM32L4XX的环境光传感器(AS7343-DLGMN)应用程序设计

define AS7343_STATUS_SPECTRAL_INT (1 << 3) /* 光谱数据就绪 */#define AS7343_SYS_CFG_SPECTRAL_EN (1 << 1) /* 光谱测量使能 */#define AS7343_SYS_CFG_ALS_EN (1 << 0) /* ALS使能 */#define AS7343_SYS_CFG_INT_EN (1 << 4) /* 中断使能 *//* 切换通道组 (0=组1 F1-F6, 1=组2 F7-F12) */

myron6688的博客 257

HashMap & ArrayMap & SparseArray

数据结构|1.8之前是数组+单链表,1,8之后再加红黑树(链表长度大于8变树,树长度减少到6时变回单链表)|两个数组,一个数组存key的hash值(从小到大排序),一个存key和value|两个数组,一个存key(从小到大排序),一个存value|+ 到注释7 8会真正插入进去,如果index不在队尾,先把index处以后的数据都往后移一位,再在mHashes数组的index处插入key的hash值,mArray的2 * index处插入key,2*index+1处插入value。

qq_15915161的博客 973

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

性能优化: HashMap & SparseArray & ArrayMap

参考: HashMap &amp;amp; SparseArray &amp;amp; ArrayMap 简单说明 安卓性能优化—使用ArrayMap与SparseArray 简介: ArrayMap与SparseArray都要比传统的HashMap 更有效率;但是当数据量达到千级以上的时候,ArrayMap与SparseArray都要比传统的HashMap 效率更低50%; ArrayMap和SparseArr...

火星男孩的分享空间 661

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an &ldquo;advanced algorithms&rdquo; book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

HashMap & SparseArray & ArrayMap 简单说明

HashMap 使用有限一维拉链数组存储结构,鉴于所用Entry结构{key,value,nextExtry},Key的hash值用于取余获得所属的数组行下标,通过链表方式顺序存放所有余数相同的各个Entry。该数组的每个存储单元被称为“桶”。 取值时依据hash定位到行,再遍历链表定位key对应的Entry对象,并通过此方式解决哈希冲突问题。 当Entry总数据量&gt;数组Le...

weixin_34195546的博客 76

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Android集合之SparseArray、ArrayMap详解

前言 作为一个Anndroid开发人员来说,我们大多数情况下时使用的Java语言,自然在一些数据的处理时,使用到的集合框架也是Java的,比如HashMap、HashSet等,但是你可否知道,Android因为自身特殊的需求,也为自己量身定制了“专属”的集合类,查阅官方文档,android.util包下,一共捕获如下几个类:SparseArray系列(SparseArray,SparseBool...

黄庆庆的世界 3万+

HashMap与ArrayMap(和SparseArray)的比较与选择

HashMap和ArrayMap的实现分析 SparseArray实现分析 比较和选择

hohoho get it up 3974

SparseArray与ArrayMap

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

dyf128的专栏 2126

Android特有的数据结构SparseArray,ArrayMap

Android特有的数据结构有 ArrayMap ArraySet SparseArray 首先来看SparseArray, 该类的官方说明:(自己更改了些) SparseArray是类型的Map,比HashMap&lt;Integers, Object&gt;的内存效率更高,因为避免了对int的封装,并且不依赖于Entry结构。 SparseArray比HashMap更省内存,它对数据采取了...

qq_37704124的博客 1076

深入理解 Android 中的 Bundle、SparseArray 和 ArrayMap

在 Android 中通过优化内存和提升性能,解决了传统数据结构在资源受限的移动设备上的一些问题。在 Android 开发中,性能是至关重要的,尤其是在内存和效率方面。若数组的长度大于 8 且存储的数据量小于数组容量的 1/3,则会进行缩容操作。通过两个独立的数组来存储键和值,避免了装箱操作,因此它在内存占用和性能上都有显著优化。的初始化相对简单,默认初始容量为 10,使用两个数组来存储数据,一个用于存储键(它的设计更注重内存的优化,在存储小规模数据时,比。使用两个数组来存储键和值,其中一个数组存储键的。

dm菜鸟编程的专栏 1194

一文详解 SparseArray、ArrayMap 实现原理

SparseArray与ArrayMap是Android提供的两个列表数据结构。SparseArray相比于HashMap采用的是,时间换取空间的方式来提高手机App的运行效率。而ArrayMap实现原理上也类似于SparseArray。

bjxiaxueliang的CODING小栈 2788

Android集合SparseArray、ArrayMap使用场景

避免了基本数据类型的装箱操作会定期通过gc函数来清理内存,内存利用率高数据量小的情况下,随机访问的效率更高ArrayMap使用更少的存储单元存储元素ArrayMap使用int类型的数组存储hash,使用Object类型数组存储k-v键值对,相较于HashMap使用Node存储节点,ArrayMap存储一个元素占用的内存更小。ArrayMap在扩容时容量变化更小HashMap在扩容的时候,通常会将容量扩大一倍,而ArrayMap在扩容的时候,如果元素个数超过8,最多扩大自己的1/2。

王温暖的博客 1521

SparseArray和ArrayMap

Java数据结构够多了吧,为了不同角度的性能又提出了SparseArray等系列。直译就是稀疏数组。实际好多同Map还有HashMap作比较实际有啥好比较的。HashMap的key可以除开基本类型的任意类型,但是SparseArray实际的key值是int,跟ArrayList这种数组才有可比性。ArrayList就是简单利用数组来做的。 SparseArray 也是利用数组,不过key是一个数组,value是一个数组。为啥要这么做,为啥体现稀疏性,来看看put和get方法便知。 public void p

d_o_n_g2的博客 313

Android的SparseArray和ArrayMap

参考: ArrayMap完全剖析 面试必备:ArrayMap源码解析 ArrayMap详解及源码分析

yzpbright的博客 679

SparseArray、ArrayMap 实现原理学习

一、SparseArray实现源码学习 SparseArray采用时间换取空间的方式来提高手机App的运行效率,这也是其与HashMap的区别;HashMap通过空间换取时间,查找迅速;HashMap中当table数组中内容达到总容量0.75时,则扩展为当前容量的两倍...

测试0901-1 128
上一篇: Java Lock
下一篇: Android SurfaceView & TextureView
_蓝橙
博客等级 码龄7年 1179粉丝 174原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值