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性能优化的使用方法,感兴趣的小伙伴们可以参考一下 立即下载

相关推荐

机器学习之性能度量

废话不说,本文分为两个部分: 第一部分,我对周志华教授《机器学习》这本书中性能度量知识点中疑难点的学习感悟;第二部分,我感觉该书2.3节 性能度量 中最后部分的代价曲线表述有误,苦于没找到联系教授的正确方式,故希望与广大网友一起探讨。

hustqb的博客 4628

深度解读ArrayMap优势与缺陷

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

许进进的博客 937

电机驱动技术中关于磁阻转矩生成的理解

正交在物理学和数学中指的是两个方向或两个向量之间的夹角为90°(直角)。在图中,当气隙磁场的轴线与转子轴线的夹角为90°时,我们称它们为正交。转子磁极的方向。通常由转子的磁极中心指向另一极的连线表示。转子轴线用图示中的d 轴表示。通过对定子、转子、气隙磁场、磁力线的理解,我们可以清晰地分析不同角度下电磁转矩的方向。这种分析不仅有助于电机的理论学习,还能为实际设计提供重要参考。掌握这些基础知识后,可以更好地理解电机工作原理及优化其性能。

weixin_48327795的博客 2074

SparseArray 你不知道的东西

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

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

Anomalib实战:5分钟搞定图像异常检测模型训练(附完整代码)

本文提供了一份基于Anomalib框架的图像异常检测快速实战指南。文章详细介绍了从环境搭建、数据准备到模型训练与推理的完整流程,重点推荐了训练速度快、效果稳定的PatchCore模型,并附带了可运行的完整代码,旨在帮助开发者快速上手工业质检等实际应用。

weixin_29039773的博客 420

STM32N6:MCU+NPU架构如何重塑边缘AI部署新范式

STM32N6作为业界首款MCU+NPU架构的通用微控制器,通过集成600 GOPS算力的NPU与800MHz Cortex-M55内核,实现了边缘AI部署的革命性突破。该方案在工业视觉和智能家居等场景中,以超低功耗和成本提供实时AI处理能力,性能较传统MCU提升超100倍,重塑了边缘智能设备的设计范式。

g8f9d0s1a2的博客 1291

LinkedList和ArrayList的区别

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

Bruce Lee的专栏 1135

R语言做一个 GM (1,1)灰色预测模型

累加生成是GM(1,1)模型的另一个重要步骤,它通过构造累加生成序列,把非线性非平稳时间序列转化为线性平稳时间序列。GM(1,1)是一种基于灰色系统理论的预测模型,通常用于中小样本的非线性、非平稳时间序列数据分析。灰色预测模型的核心是灰度处理,将原始时间序列转化为灰色时间序列。这里使用R语言中的diff函数对时间序列进行一次差分,然后对结果取累加和得到灰度序列。以上是GM(1,1)灰色预测模型在R语言中的实现步骤。需要注意的是,GM(1,1)模型适用于中小样本的时间序列预测,对于长期预测效果可能较差。

Mrrunsen的博客 3841

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

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

小唯的博客 556

SRS流媒体服务器在Windows下的安装

在之前的流媒体开发中(视频会议),我基本上使用nginx加模块的方式进行学习、测试,正式开发的时候改为服务器端用EasyDarwin,客户端用rtsp-simple-server(这些流媒体服务器的用法见我以前的博文),这样可以充分利用客户端的资源,降低服务器端的压力。在流媒体协议方案,我选择相对较快的rtsp。这个协议优点是支持UDP协议,优化好的环境下可以实现3秒以下的延迟,基本满足甲方要求,缺点就是不支持网页播放。

dgnankai的专栏 2023

【全网首发】2026华为OD双机位C卷 机考真题题库含考点说明以及在线OJ (Java)

如果你收到的是双机位C卷考试通知,需要针对性地调整备考策略。自2025年11月19日起,华为OD机试已正式从双机位A卷切换至。复杂度明显提升,需要组合多个算法点。题面相对简单,直接考查编程基本功。考查问题分析、算法选择和优化能力。通常为1-2个核心算法点的应用。

算法大师! 165

菜鸟看源码之SparseArray

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

leilifengxingmw的博客 704

600份国家自然基金申报书--模板

600份国家自然基金申报书--模板

需要远程指导仿真实验、代码有问题的,请后台私信或者关注公众号 4186

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

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

性能优化: HashMap & SparseArray & ArrayMap

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

火星男孩的分享空间 661

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

HashMap & SparseArray & ArrayMap 简单说明

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

weixin_34195546的博客 76

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

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、付费专栏及课程。

余额充值