在 Android 开发中集合是处理数据的核心工具 —— 从列表展示如 RecyclerView 数据源到键值缓存如用户信息存储几乎所有场景都离不开集合。但 Android 集合体系不仅包含 Java 标准集合如 ArrayList、HashMap还有专为移动设备优化的Android 特有集合如 SparseArray、ArrayMap。本文将从特性、区别、优势、调用示例、性能五个维度系统梳理 Android 常用集合帮你在开发中精准选型。一、集合体系总览先搞懂分类Android 集合本质是对 Java 集合框架的扩展核心分为三大类每类对应不同的数据结构和使用场景集合类型核心作用常用实现类关键特点List有序、可重复的数据存储ArrayList、LinkedList、Vector按索引访问元素可重复Map键值对Key-Value存储HashMap、SparseArray、ArrayMap、TreeMap键唯一值可重复Set无序、不可重复的数据存储HashSet、TreeSet、LinkedHashSet元素唯一基于 Map 实现核心差异点List 强调 “顺序”支持按索引操作Map 强调 “映射”通过键快速查找值Set 强调 “唯一性”本质是 “只存键不存值” 的 Map。二、List 集合家族有序数据的选择List 是 Android 中最常用的集合如 RecyclerView 的 adapter 数据源核心解决 “有序数据的存储与访问” 问题。重点分析 ArrayList 和 LinkedListVector 因线程安全开销大已很少用。2.1 ArrayList动态数组随机访问王者特性底层基于动态数组实现初始化时默认容量为 10可指定初始容量当容量不足时自动扩容为原容量的 1.5 倍计算方式newCapacity oldCapacity (oldCapacity 1)支持快速随机访问通过索引 get(int index)但增删中间元素时需移动数组元素效率较低。优势与区别对比维度ArrayListLinkedList数据结构动态数组双向链表随机访问get快O (1)慢O (n)需遍历链表增删中间元素慢O (n)移动数组快O (1)仅需修改指针内存占用连续内存可能有扩容浪费非连续内存每个元素含指针适用场景频繁读、少量增删频繁增删、少量读调用示例Kotlin/Java// Kotlin 示例 fun useArrayList() { // 1. 创建指定初始容量为 20避免频繁扩容 val arrayList ArrayListString(20) // 2. 添加元素末尾添加O(1)中间添加O(n) arrayList.add(Apple) // 末尾添加 arrayList.add(1, Banana) // 索引 1 处添加需移动后续元素 // 3. 删除元素按索引O(n)按元素O(n) arrayList.removeAt(0) // 删除索引 0 元素 arrayList.remove(Banana) // 删除指定元素需先查找 // 4. 遍历推荐 for-each 或索引遍历效率高 // 方式1索引遍历随机访问优势体现 for (i in arrayList.indices) { Log.d(ArrayList, 元素${arrayList[i]}) } // 方式2for-each 遍历 for (fruit in arrayList) { Log.d(ArrayList, 元素$fruit) } // 5. 其他常用操作 arrayList.contains(Apple) // 判断是否包含O(n) arrayList.clear() // 清空集合O(n) } // Java 示例关键差异需指定泛型方法调用语法 ListString arrayList new ArrayList(20); arrayList.add(Apple); for (int i 0; i arrayList.size(); i) { Log.d(ArrayList, 元素 arrayList.get(i)); }性能分析时间复杂度随机访问get(int)O (1)直接通过数组索引定位末尾添加add(E)O (1) amortized多数情况无需扩容扩容时为 O (n)中间增删add(int, E)/removeAt(int)O (n)需移动数组元素查找contains(E)O (n)需遍历数组。内存优化建议初始化时指定预估容量如已知存储 100 条数据初始容量设为 100避免频繁扩容导致的内存浪费和性能开销。2.2 LinkedList双向链表增删能手特性底层基于双向链表实现每个元素Node包含 prev前驱指针、next后继指针和 item元素值不支持随机访问需从链表头 / 尾遍历到目标索引增删元素时仅需修改指针指向无需移动大量数据效率高。优势与区别见 2.1 节的对比表核心优势是频繁增删中间元素时性能优于 ArrayList。调用示例Kotlinfun useLinkedList() { val linkedList LinkedListString() // 1. 添加元素头部/尾部/中间O(1) 或 O(n) linkedList.addFirst(Head) // 头部添加O(1) linkedList.addLast(Tail) // 尾部添加O(1) linkedList.add(1, Middle) // 中间添加需先遍历到索引 1O(n) // 2. 删除元素头部/尾部 O(1)中间 O(n) linkedList.removeFirst() // 头部删除O(1) linkedList.removeLast() // 尾部删除O(1) // 3. 遍历不推荐索引遍历O(n²) 性能差 // 推荐方式for-each 或迭代器O(n) for (item in linkedList) { Log.d(LinkedList, 元素$item) } // 4. 特有方法利用链表特性 linkedList.peekFirst() // 获取头部元素不删除O(1) linkedList.pollLast() // 获取并删除尾部元素O(1) }性能分析时间复杂度头部 / 尾部增删addFirst/removeLastO (1)直接修改首尾指针中间增删add(int, E)/removeAt(int)O (n)需遍历到目标索引随机访问get(int)O (n)需从头部 / 尾部遍历查找contains(E)O (n)需遍历链表。注意避坑绝对不要用 for (i in 0 until linkedList.size) 遍历 LinkedList—— 每次 linkedList.get(i) 都会从头遍历总时间复杂度为 O (n²)数据量大时会严重卡顿三、Map 集合家族键值对存储的最优解Map 用于 “通过键快速查找值”是 Android 中缓存数据的核心工具如存储用户信息、配置参数。重点分析Java 标准 MapHashMap和Android 特有优化 MapSparseArray、ArrayMap这三类是开发中最常用的。3.1 HashMapJava 标准键值对通用性强特性底层基于数组 链表 / 红黑树实现JDK 1.8数组存储 Node键值对冲突时用链表解决链表长度超过 8 时转为红黑树键Key允许为 null仅一个值Value允许为 null无序存储迭代顺序与插入顺序无关默认初始容量 16负载因子 0.75容量达到 16*0.7512 时扩容为 32。优势与区别对比 Android 特有 Map对比维度HashMapSparseArrayArrayMap键类型任意对象如 String仅 int任意对象装箱开销有如 int → Integer无直接存 int有但比 HashMap 小内存占用高Entry 对象 链表低双数组存储中双数组存储时间复杂度get/putO(1)get/putO(log n)get/putO(log n)适用场景键非 int、数据量大键为 int、数据量中小键任意、数据量小1000调用示例Kotlinfun useHashMap() { // 1. 创建初始容量 32负载因子 0.75默认 val hashMap HashMapString, Int(32) // 2. 添加键值对O(1)冲突时 O(log n) hashMap[Apple] 10 // 键String值Int hashMap[Banana] 5 hashMap[null] 3 // 键为 null仅允许一个 // 3. 获取值O(1)通过键的 hash 定位 val appleCount hashMap[Apple] ?: 0 // 无值时默认 0 // 4. 删除键值对O(1) hashMap.remove(Banana) // 5. 遍历三种方式 // 方式1遍历键 for (key in hashMap.keys) { Log.d(HashMap, 键$key值${hashMap[key]}) } // 方式2遍历键值对推荐 for ((key, value) in hashMap) { Log.d(HashMap, 键$key值$value) } // 方式3遍历值不推荐无法获取键 for (value in hashMap.values) { Log.d(HashMap, 值$value) } }性能分析时间复杂度put(K, V)/get(K)O (1)理想情况无 hash 冲突冲突时链表 O (n)红黑树 O (log n)remove(K)O (1) 或 O (log n)同 put/get。Android 中的问题键为 int 时如存储 ID 对应的数据会产生自动装箱开销int → Integer且每个 Entry 对象会占用额外内存存储 hash、key、value、next 指针在内存紧张的移动设备上不够优化。3.2 SparseArrayAndroid 特有int 键的最优解特性专为int 类型键优化的 Map底层基于两个数组实现int[] keys存储键有序、Object[] values存储值与键索引对应无自动装箱开销直接存储 int 键无需转为 Integer通过二分查找定位键的索引O (log n)内存占用仅为 HashMap 的 1/3 左右。优势内存更优无 Entry 对象开销双数组存储更紧凑无装箱开销键为 int 时避免 int → Integer 的转换API 简洁针对 int 键设计无需泛型声明键类型。调用示例Kotlinfun useSparseArray() { // 1. 创建SparseArrayValue类型初始容量 10默认 val sparseArray SparseArrayString(10) // 2. 添加键值对O(log n)二分查找键位置 sparseArray.put(1, Apple) // 键int值String sparseArray.put(2, Banana) sparseArray.put(3, Cherry) // 3. 获取值O(log n) val value sparseArray.get(2) // 直接传 int 键无需装箱 val defaultValue sparseArray.get(4, Default) // 无键时返回默认值 // 4. 删除键值对O(log n) 查找 O(n) 移动数组 sparseArray.delete(3) // 按键删除 sparseArray.removeAt(0) // 按索引删除更高效 // 5. 遍历两种方式均为 O(n) // 方式1索引遍历推荐效率高 for (i in 0 until sparseArray.size()) { val key sparseArray.keyAt(i) val value sparseArray.valueAt(i) Log.d(SparseArray, 键$key值$value) } // 方式2迭代器API 24 支持 val iterator sparseArray.valueIterator() while (iterator.hasNext()) { Log.d(SparseArray, 值${iterator.next()}) } }性能分析时间复杂度put(int, V)/get(int)O (log n)二分查找键的位置delete(int)O (log n) 查找 O (n) 移动数组删除后需整理数组遍历O (n)直接遍历数组无额外开销。适用场景键为 int 类型、数据量中小10000的场景如 RecyclerView 的 item 数据缓存、ID 与对象的映射如用户 ID 对应用户信息。避坑数据量极大10000时O(log n) 的时间复杂度会比 HashMap 的 O(1) 慢此时推荐用 HashMap。3.3 ArrayMapAndroid 特有小数据量通用键值对特性底层基于两个数组实现int[] hashes存储键的 hash 值有序、Object[] array存储键值对按 “键 1、值 1、键 2、值 2” 顺序排列支持任意类型键如 String、Integer无 Entry 对象开销内存比 HashMap 节省约 50%通过二分查找 hash 值定位键O (log n)适合数据量小的场景。优势与区别对比 HashMap内存更优无 Entry 对象双数组存储适合内存紧张的移动设备扩容成本低扩容时仅需复制两个小数组比 HashMap 复制大数组开销小缺点数据量超过 1000 时O(log n) 的查找效率不如 HashMap 的 O(1)。调用示例Kotlinfun useArrayMap() { // 1. 创建ArrayMapKey类型, Value类型初始容量 10 val arrayMap ArrayMapString, Int(10) // 2. 添加键值对O(log n) arrayMap[Apple] 10 arrayMap[Banana] 5 // 3. 获取值O(log n) val count arrayMap[Apple] ?: 0 // 4. 删除键值对O(log n) 查找 O(n) 移动数组 arrayMap.remove(Banana) // 5. 遍历同 SparseArray索引遍历效率高 for (i in 0 until arrayMap.size) { val key arrayMap.keyAt(i) val value arrayMap.valueAt(i) Log.d(ArrayMap, 键$key值$value) } }性能分析时间复杂度与 SparseArray 一致put/get/delete 均为 O (log n)适用场景任意类型键、数据量小1000的场景如配置参数存储、临时缓存如页面状态不适用场景数据量大1000或频繁查找的场景此时 HashMap 更优。四、Set 集合家族不可重复数据的存储Set 本质是 “仅存储键的 Map”—— 通过 Map 的 “键唯一性” 实现元素不可重复。核心实现类与 Map 一一对应特性和性能高度一致。Set 实现类底层依赖的 Map核心特性适用场景HashSetHashMap无序、元素可 null、效率高无需有序仅需去重TreeSetTreeMap有序自然排序、无 null需要按元素顺序存储LinkedHashSetLinkedHashMap有序插入顺序、无 null需要保留插入顺序的去重4.1 HashSet最常用的去重集合特性底层基于 HashMap 实现将元素作为 HashMap 的键值为固定的 PRESENT 对象无序迭代顺序与插入顺序无关元素可 null仅一个不可重复通过 equals() 和 hashCode() 判断唯一性。调用示例Kotlinfun useHashSet() { val hashSet HashSetString() // 添加元素重复元素会自动去重 hashSet.add(Apple) hashSet.add(Apple) // 重复添加无效果 hashSet.add(null) // 允许一个 null // 删除元素 hashSet.remove(Apple) // 遍历for-each 或迭代器 for (item in hashSet) { Log.d(HashSet, 元素$item) } // 关键方法 hashSet.contains(Banana) // 判断是否包含O(1) hashSet.isEmpty() // 判断是否为空 }性能分析时间复杂度与 HashMap 一致add/remove/contains 均为 O (1)适用场景仅需去重、无需有序的场景如存储用户标签、去重列表。4.2 TreeSet有序的去重集合特性底层基于 TreeMap 实现元素按自然排序如 String 按字母序Integer 按数值序或自定义排序无序插入顺序但迭代时按排序后的顺序输出元素不可 null不可重复。调用示例Kotlinfun useTreeSet() { // 1. 自然排序Integer 按数值升序 val treeSet1 TreeSetInt() treeSet1.add(3) treeSet1.add(1) treeSet1.add(2) Log.d(TreeSet, treeSet1.toString()) // 输出 [1, 2, 3] // 2. 自定义排序String 按长度降序 val treeSet2 TreeSetString(Comparator { s1, s2 - s2.length - s1.length // 降序长的在前 }) treeSet2.add(Apple) // 5 个字符 treeSet2.add(Banana) // 6 个字符 treeSet2.add(Cherry) // 5 个字符 Log.d(TreeSet, treeSet2.toString()) // 输出 [Banana, Apple, Cherry] }性能分析时间复杂度与 TreeMap 一致add/remove/contains 均为 O (log n)适用场景需要按元素顺序存储的去重场景如排行榜、有序标签列表。五、Android 集合选择指南精准选型不踩坑结合前面的分析总结不同场景下的最优集合选择场景需求推荐集合不推荐集合列表展示频繁读、少量增删ArrayListLinkedList频繁增删中间元素如队列LinkedListArrayList键为 int、数据量中小SparseArrayHashMap键任意、数据量小1000ArrayMapHashMap键任意、数据量大1000HashMapArrayMap仅需去重、无需有序HashSetTreeSet需要有序去重自然排序TreeSetHashSet需要保留插入顺序的去重LinkedHashSetHashSet六、性能优化小贴士让集合更高效1.初始化指定容量如 ArrayList(100)、HashMap(200)避免频繁扩容导致的内存浪费和性能开销。2.优先用 Android 特有集合键为 int 时用 SparseArray 替代 HashMap数据量小时用 ArrayMap 替代 HashMap减少内存占用和装箱开销。3.避免遍历性能坑不使用索引遍历 LinkedListO(n²)遍历 SparseArray/ArrayMap 时用索引遍历keyAt(i)/valueAt(i)而非 for-each底层仍需遍历索引但代码更简洁。4.集合判空用isEmpty()避免用 size() 0isEmpty() 是更高效的判断方式多数集合直接返回内部标志无需计算大小。5.大数据量避免自动装箱如 SparseIntArray存储 int 值、SparseLongArray存储 long 值比 SparseArrayInt 更省内存避免 int → Integer 装箱。七、总结Android 集合选型的核心是“匹配场景”有序数据看操作类型读多写少用 ArrayList写多读少用 LinkedList键值对看键类型和数据量int 键用 SparseArray小数据量用 ArrayMap大数据量用 HashMap去重数据看是否有序无序用 HashSet有序用 TreeSet。掌握不同集合的特性和性能差异不仅能提升代码效率还能减少内存占用 —— 在 Android 开发中“小而优” 的集合选择往往是提升 App 流畅度的关键。
Android 集合全解析
在 Android 开发中集合是处理数据的核心工具 —— 从列表展示如 RecyclerView 数据源到键值缓存如用户信息存储几乎所有场景都离不开集合。但 Android 集合体系不仅包含 Java 标准集合如 ArrayList、HashMap还有专为移动设备优化的Android 特有集合如 SparseArray、ArrayMap。本文将从特性、区别、优势、调用示例、性能五个维度系统梳理 Android 常用集合帮你在开发中精准选型。一、集合体系总览先搞懂分类Android 集合本质是对 Java 集合框架的扩展核心分为三大类每类对应不同的数据结构和使用场景集合类型核心作用常用实现类关键特点List有序、可重复的数据存储ArrayList、LinkedList、Vector按索引访问元素可重复Map键值对Key-Value存储HashMap、SparseArray、ArrayMap、TreeMap键唯一值可重复Set无序、不可重复的数据存储HashSet、TreeSet、LinkedHashSet元素唯一基于 Map 实现核心差异点List 强调 “顺序”支持按索引操作Map 强调 “映射”通过键快速查找值Set 强调 “唯一性”本质是 “只存键不存值” 的 Map。二、List 集合家族有序数据的选择List 是 Android 中最常用的集合如 RecyclerView 的 adapter 数据源核心解决 “有序数据的存储与访问” 问题。重点分析 ArrayList 和 LinkedListVector 因线程安全开销大已很少用。2.1 ArrayList动态数组随机访问王者特性底层基于动态数组实现初始化时默认容量为 10可指定初始容量当容量不足时自动扩容为原容量的 1.5 倍计算方式newCapacity oldCapacity (oldCapacity 1)支持快速随机访问通过索引 get(int index)但增删中间元素时需移动数组元素效率较低。优势与区别对比维度ArrayListLinkedList数据结构动态数组双向链表随机访问get快O (1)慢O (n)需遍历链表增删中间元素慢O (n)移动数组快O (1)仅需修改指针内存占用连续内存可能有扩容浪费非连续内存每个元素含指针适用场景频繁读、少量增删频繁增删、少量读调用示例Kotlin/Java// Kotlin 示例 fun useArrayList() { // 1. 创建指定初始容量为 20避免频繁扩容 val arrayList ArrayListString(20) // 2. 添加元素末尾添加O(1)中间添加O(n) arrayList.add(Apple) // 末尾添加 arrayList.add(1, Banana) // 索引 1 处添加需移动后续元素 // 3. 删除元素按索引O(n)按元素O(n) arrayList.removeAt(0) // 删除索引 0 元素 arrayList.remove(Banana) // 删除指定元素需先查找 // 4. 遍历推荐 for-each 或索引遍历效率高 // 方式1索引遍历随机访问优势体现 for (i in arrayList.indices) { Log.d(ArrayList, 元素${arrayList[i]}) } // 方式2for-each 遍历 for (fruit in arrayList) { Log.d(ArrayList, 元素$fruit) } // 5. 其他常用操作 arrayList.contains(Apple) // 判断是否包含O(n) arrayList.clear() // 清空集合O(n) } // Java 示例关键差异需指定泛型方法调用语法 ListString arrayList new ArrayList(20); arrayList.add(Apple); for (int i 0; i arrayList.size(); i) { Log.d(ArrayList, 元素 arrayList.get(i)); }性能分析时间复杂度随机访问get(int)O (1)直接通过数组索引定位末尾添加add(E)O (1) amortized多数情况无需扩容扩容时为 O (n)中间增删add(int, E)/removeAt(int)O (n)需移动数组元素查找contains(E)O (n)需遍历数组。内存优化建议初始化时指定预估容量如已知存储 100 条数据初始容量设为 100避免频繁扩容导致的内存浪费和性能开销。2.2 LinkedList双向链表增删能手特性底层基于双向链表实现每个元素Node包含 prev前驱指针、next后继指针和 item元素值不支持随机访问需从链表头 / 尾遍历到目标索引增删元素时仅需修改指针指向无需移动大量数据效率高。优势与区别见 2.1 节的对比表核心优势是频繁增删中间元素时性能优于 ArrayList。调用示例Kotlinfun useLinkedList() { val linkedList LinkedListString() // 1. 添加元素头部/尾部/中间O(1) 或 O(n) linkedList.addFirst(Head) // 头部添加O(1) linkedList.addLast(Tail) // 尾部添加O(1) linkedList.add(1, Middle) // 中间添加需先遍历到索引 1O(n) // 2. 删除元素头部/尾部 O(1)中间 O(n) linkedList.removeFirst() // 头部删除O(1) linkedList.removeLast() // 尾部删除O(1) // 3. 遍历不推荐索引遍历O(n²) 性能差 // 推荐方式for-each 或迭代器O(n) for (item in linkedList) { Log.d(LinkedList, 元素$item) } // 4. 特有方法利用链表特性 linkedList.peekFirst() // 获取头部元素不删除O(1) linkedList.pollLast() // 获取并删除尾部元素O(1) }性能分析时间复杂度头部 / 尾部增删addFirst/removeLastO (1)直接修改首尾指针中间增删add(int, E)/removeAt(int)O (n)需遍历到目标索引随机访问get(int)O (n)需从头部 / 尾部遍历查找contains(E)O (n)需遍历链表。注意避坑绝对不要用 for (i in 0 until linkedList.size) 遍历 LinkedList—— 每次 linkedList.get(i) 都会从头遍历总时间复杂度为 O (n²)数据量大时会严重卡顿三、Map 集合家族键值对存储的最优解Map 用于 “通过键快速查找值”是 Android 中缓存数据的核心工具如存储用户信息、配置参数。重点分析Java 标准 MapHashMap和Android 特有优化 MapSparseArray、ArrayMap这三类是开发中最常用的。3.1 HashMapJava 标准键值对通用性强特性底层基于数组 链表 / 红黑树实现JDK 1.8数组存储 Node键值对冲突时用链表解决链表长度超过 8 时转为红黑树键Key允许为 null仅一个值Value允许为 null无序存储迭代顺序与插入顺序无关默认初始容量 16负载因子 0.75容量达到 16*0.7512 时扩容为 32。优势与区别对比 Android 特有 Map对比维度HashMapSparseArrayArrayMap键类型任意对象如 String仅 int任意对象装箱开销有如 int → Integer无直接存 int有但比 HashMap 小内存占用高Entry 对象 链表低双数组存储中双数组存储时间复杂度get/putO(1)get/putO(log n)get/putO(log n)适用场景键非 int、数据量大键为 int、数据量中小键任意、数据量小1000调用示例Kotlinfun useHashMap() { // 1. 创建初始容量 32负载因子 0.75默认 val hashMap HashMapString, Int(32) // 2. 添加键值对O(1)冲突时 O(log n) hashMap[Apple] 10 // 键String值Int hashMap[Banana] 5 hashMap[null] 3 // 键为 null仅允许一个 // 3. 获取值O(1)通过键的 hash 定位 val appleCount hashMap[Apple] ?: 0 // 无值时默认 0 // 4. 删除键值对O(1) hashMap.remove(Banana) // 5. 遍历三种方式 // 方式1遍历键 for (key in hashMap.keys) { Log.d(HashMap, 键$key值${hashMap[key]}) } // 方式2遍历键值对推荐 for ((key, value) in hashMap) { Log.d(HashMap, 键$key值$value) } // 方式3遍历值不推荐无法获取键 for (value in hashMap.values) { Log.d(HashMap, 值$value) } }性能分析时间复杂度put(K, V)/get(K)O (1)理想情况无 hash 冲突冲突时链表 O (n)红黑树 O (log n)remove(K)O (1) 或 O (log n)同 put/get。Android 中的问题键为 int 时如存储 ID 对应的数据会产生自动装箱开销int → Integer且每个 Entry 对象会占用额外内存存储 hash、key、value、next 指针在内存紧张的移动设备上不够优化。3.2 SparseArrayAndroid 特有int 键的最优解特性专为int 类型键优化的 Map底层基于两个数组实现int[] keys存储键有序、Object[] values存储值与键索引对应无自动装箱开销直接存储 int 键无需转为 Integer通过二分查找定位键的索引O (log n)内存占用仅为 HashMap 的 1/3 左右。优势内存更优无 Entry 对象开销双数组存储更紧凑无装箱开销键为 int 时避免 int → Integer 的转换API 简洁针对 int 键设计无需泛型声明键类型。调用示例Kotlinfun useSparseArray() { // 1. 创建SparseArrayValue类型初始容量 10默认 val sparseArray SparseArrayString(10) // 2. 添加键值对O(log n)二分查找键位置 sparseArray.put(1, Apple) // 键int值String sparseArray.put(2, Banana) sparseArray.put(3, Cherry) // 3. 获取值O(log n) val value sparseArray.get(2) // 直接传 int 键无需装箱 val defaultValue sparseArray.get(4, Default) // 无键时返回默认值 // 4. 删除键值对O(log n) 查找 O(n) 移动数组 sparseArray.delete(3) // 按键删除 sparseArray.removeAt(0) // 按索引删除更高效 // 5. 遍历两种方式均为 O(n) // 方式1索引遍历推荐效率高 for (i in 0 until sparseArray.size()) { val key sparseArray.keyAt(i) val value sparseArray.valueAt(i) Log.d(SparseArray, 键$key值$value) } // 方式2迭代器API 24 支持 val iterator sparseArray.valueIterator() while (iterator.hasNext()) { Log.d(SparseArray, 值${iterator.next()}) } }性能分析时间复杂度put(int, V)/get(int)O (log n)二分查找键的位置delete(int)O (log n) 查找 O (n) 移动数组删除后需整理数组遍历O (n)直接遍历数组无额外开销。适用场景键为 int 类型、数据量中小10000的场景如 RecyclerView 的 item 数据缓存、ID 与对象的映射如用户 ID 对应用户信息。避坑数据量极大10000时O(log n) 的时间复杂度会比 HashMap 的 O(1) 慢此时推荐用 HashMap。3.3 ArrayMapAndroid 特有小数据量通用键值对特性底层基于两个数组实现int[] hashes存储键的 hash 值有序、Object[] array存储键值对按 “键 1、值 1、键 2、值 2” 顺序排列支持任意类型键如 String、Integer无 Entry 对象开销内存比 HashMap 节省约 50%通过二分查找 hash 值定位键O (log n)适合数据量小的场景。优势与区别对比 HashMap内存更优无 Entry 对象双数组存储适合内存紧张的移动设备扩容成本低扩容时仅需复制两个小数组比 HashMap 复制大数组开销小缺点数据量超过 1000 时O(log n) 的查找效率不如 HashMap 的 O(1)。调用示例Kotlinfun useArrayMap() { // 1. 创建ArrayMapKey类型, Value类型初始容量 10 val arrayMap ArrayMapString, Int(10) // 2. 添加键值对O(log n) arrayMap[Apple] 10 arrayMap[Banana] 5 // 3. 获取值O(log n) val count arrayMap[Apple] ?: 0 // 4. 删除键值对O(log n) 查找 O(n) 移动数组 arrayMap.remove(Banana) // 5. 遍历同 SparseArray索引遍历效率高 for (i in 0 until arrayMap.size) { val key arrayMap.keyAt(i) val value arrayMap.valueAt(i) Log.d(ArrayMap, 键$key值$value) } }性能分析时间复杂度与 SparseArray 一致put/get/delete 均为 O (log n)适用场景任意类型键、数据量小1000的场景如配置参数存储、临时缓存如页面状态不适用场景数据量大1000或频繁查找的场景此时 HashMap 更优。四、Set 集合家族不可重复数据的存储Set 本质是 “仅存储键的 Map”—— 通过 Map 的 “键唯一性” 实现元素不可重复。核心实现类与 Map 一一对应特性和性能高度一致。Set 实现类底层依赖的 Map核心特性适用场景HashSetHashMap无序、元素可 null、效率高无需有序仅需去重TreeSetTreeMap有序自然排序、无 null需要按元素顺序存储LinkedHashSetLinkedHashMap有序插入顺序、无 null需要保留插入顺序的去重4.1 HashSet最常用的去重集合特性底层基于 HashMap 实现将元素作为 HashMap 的键值为固定的 PRESENT 对象无序迭代顺序与插入顺序无关元素可 null仅一个不可重复通过 equals() 和 hashCode() 判断唯一性。调用示例Kotlinfun useHashSet() { val hashSet HashSetString() // 添加元素重复元素会自动去重 hashSet.add(Apple) hashSet.add(Apple) // 重复添加无效果 hashSet.add(null) // 允许一个 null // 删除元素 hashSet.remove(Apple) // 遍历for-each 或迭代器 for (item in hashSet) { Log.d(HashSet, 元素$item) } // 关键方法 hashSet.contains(Banana) // 判断是否包含O(1) hashSet.isEmpty() // 判断是否为空 }性能分析时间复杂度与 HashMap 一致add/remove/contains 均为 O (1)适用场景仅需去重、无需有序的场景如存储用户标签、去重列表。4.2 TreeSet有序的去重集合特性底层基于 TreeMap 实现元素按自然排序如 String 按字母序Integer 按数值序或自定义排序无序插入顺序但迭代时按排序后的顺序输出元素不可 null不可重复。调用示例Kotlinfun useTreeSet() { // 1. 自然排序Integer 按数值升序 val treeSet1 TreeSetInt() treeSet1.add(3) treeSet1.add(1) treeSet1.add(2) Log.d(TreeSet, treeSet1.toString()) // 输出 [1, 2, 3] // 2. 自定义排序String 按长度降序 val treeSet2 TreeSetString(Comparator { s1, s2 - s2.length - s1.length // 降序长的在前 }) treeSet2.add(Apple) // 5 个字符 treeSet2.add(Banana) // 6 个字符 treeSet2.add(Cherry) // 5 个字符 Log.d(TreeSet, treeSet2.toString()) // 输出 [Banana, Apple, Cherry] }性能分析时间复杂度与 TreeMap 一致add/remove/contains 均为 O (log n)适用场景需要按元素顺序存储的去重场景如排行榜、有序标签列表。五、Android 集合选择指南精准选型不踩坑结合前面的分析总结不同场景下的最优集合选择场景需求推荐集合不推荐集合列表展示频繁读、少量增删ArrayListLinkedList频繁增删中间元素如队列LinkedListArrayList键为 int、数据量中小SparseArrayHashMap键任意、数据量小1000ArrayMapHashMap键任意、数据量大1000HashMapArrayMap仅需去重、无需有序HashSetTreeSet需要有序去重自然排序TreeSetHashSet需要保留插入顺序的去重LinkedHashSetHashSet六、性能优化小贴士让集合更高效1.初始化指定容量如 ArrayList(100)、HashMap(200)避免频繁扩容导致的内存浪费和性能开销。2.优先用 Android 特有集合键为 int 时用 SparseArray 替代 HashMap数据量小时用 ArrayMap 替代 HashMap减少内存占用和装箱开销。3.避免遍历性能坑不使用索引遍历 LinkedListO(n²)遍历 SparseArray/ArrayMap 时用索引遍历keyAt(i)/valueAt(i)而非 for-each底层仍需遍历索引但代码更简洁。4.集合判空用isEmpty()避免用 size() 0isEmpty() 是更高效的判断方式多数集合直接返回内部标志无需计算大小。5.大数据量避免自动装箱如 SparseIntArray存储 int 值、SparseLongArray存储 long 值比 SparseArrayInt 更省内存避免 int → Integer 装箱。七、总结Android 集合选型的核心是“匹配场景”有序数据看操作类型读多写少用 ArrayList写多读少用 LinkedList键值对看键类型和数据量int 键用 SparseArray小数据量用 ArrayMap大数据量用 HashMap去重数据看是否有序无序用 HashSet有序用 TreeSet。掌握不同集合的特性和性能差异不仅能提升代码效率还能减少内存占用 —— 在 Android 开发中“小而优” 的集合选择往往是提升 App 流畅度的关键。