ArrayMap 和 SparseArray 是 Android 中优化内存和性能的数据结构,专为移动端场景设计。它们在 HashMap 的基础上做了以下改进:
一、HashMap 的痛点
-
内存开销大:
- 每个键值对需封装成
Entry对象(包含键、值、哈希值、指针)。 - 自动装箱(如
int→Integer)增加内存占用。
- 每个键值对需封装成
-
扩容成本高:动态扩容需重建哈希表,频繁操作影响性能。
-
小数据量效率低:哈希表的数组稀疏性导致内存浪费(如存10个元素,数组长度可能为16)。
二、ArrayMap:用数组替代哈希表
1. 核心改进
-
数据结构:用两个数组分别存储键和值(无
Entry对象)。Object[] mHashes; // 存储键的哈希值(有序) Object[] mArray; // 键值交替存储:[key1, value1, key2, value2...] -
查找方式:通过 二分查找 定位键(时间复杂度 O(log n))。
-
内存优化:
- 避免
Entry对象开销,内存更紧凑。 - 扩容时直接复制数组,无需重建哈希表。
- 避免
2. 适用场景
- 小数据量(百级以内) :查找效率接近 HashMap(内存优势更明显)。
- 键值对频繁增删:内存管理更高效,减少 GC 压力。
3. 示例代码
ArrayMap<String, Integer> arrayMap = new ArrayMap<>();
arrayMap.put("Apple", 10);
arrayMap.put("Banana", 20);
int count = arrayMap.get("Apple"); // 通过二分查找定位
三、SparseArray:针对整型键的极致优化
1. 核心改进
-
键为
int类型:无需装箱(直接使用int[]数组)。 -
数据结构:
int[] mKeys; // 有序存储 int 键 Object[] mValues; // 存储值 -
延迟删除机制:删除时标记为
DELETED,批量清理时再压缩数组。 -
内存优化:无哈希表结构,无
Entry对象,内存占用极低。
2. 适用场景
- 键为整型(如 View 的 ID) :避免
HashMap<Integer, Object>的自动装箱开销。 - 频繁增删但数据量小:延迟删除提升性能。
3. 示例代码
SparseArray<String> sparseArray = new SparseArray<>();
sparseArray.put(1001, "Activity");
sparseArray.put(1002, "Fragment");
String value = sparseArray.get(1001); // 二分查找键数组
四、对比总结
| 数据结构 | 优势 | 劣势 | 适用场景 |
|---|---|---|---|
| HashMap | 查找快(O(1)),通用性强 | 内存开销大,小数据量效率低 | 大数据量、高频查找 |
| ArrayMap | 内存紧凑,小数据量性能优 | 查找慢(O(log n)) | 小数据量、键为对象类型 |
| SparseArray | 内存极致优化,整型键无装箱 | 仅支持整型键,查找慢(O(log n)) | 键为整型、小数据量 |
五、性能实测参考
-
内存占用(存100个键值对):
HashMap:约 3.5KBArrayMap:约 1.2KBSparseArray:约 0.8KB
-
查找速度(千次操作耗时):
HashMap:~1msArrayMap(100元素):~2msSparseArray(100元素):~2ms
六、使用建议
-
优先用 ArrayMap/SparseArray:
- 数据量小(<1000),键为整型或简单对象。
- 内存敏感场景(如 Android 低端设备)。
-
仍用 HashMap:
- 数据量大(>1000),或需要高频查找。
- 键为复杂对象(如
String、自定义类)。
口诀:
「安卓开发内存省,ArrayMap、SparseArray显神通
小数据量用数组,整型键值更轻松
哈希表虽快内存大,按需选择才聪明!」