目录
SparseArray
和 HashMap
是 Android 中两种不同的数据结构,用于存储键值对。它们的主要区别体现在数据结构的实现、性能优化和适用场景上。以下是它们的详细对比:
1. 概念与实现
-
SparseArray
- 是 Android 提供的一种专门优化的键值对数据结构,键为
int
类型。 - 内部通过两个数组(一个存储键,一个存储值)实现,使用二分查找来查找键的位置。
- 避免了自动装箱与拆箱(
int
与Integer
的互转),更适合处理大量int
键的情况。 - 提供多种变体:
SparseIntArray
、SparseLongArray
、SparseBooleanArray
等。
- 是 Android 提供的一种专门优化的键值对数据结构,键为
-
HashMap
- Java 标准库中的通用键值对数据结构,键和值都可以是任意对象。
- 使用哈希表实现,通过键的
hashCode
方法计算存储位置。 - 为泛型数据设计,灵活性更强,但可能因为自动装箱和内存分配导致性能开销更高。
2. 性能对比
特性 | SparseArray | HashMap |
---|---|---|
内存占用 | 更节省内存,避免了 Entry 对象的开销 | 占用更多内存,因为需要存储 Entry 对象和哈希表数据 |
性能 | 对 int 键进行了优化,效率更高 | 泛型实现,灵活但稍慢(涉及装箱、哈希计算) |
自动装箱与拆箱 | 不需要装箱,直接处理 int 键 | 需要将 int 装箱为 Integer ,增加性能开销 |
插入/删除 | 较慢(数组调整成本较高) | 较快(哈希表操作) |
查找 | 二分查找,O(log n) | 哈希查找,O(1)(理想情况下) |
3. 使用场景
-
SparseArray
- 适合场景:
- 键是
int
类型的场景。 - 数据量较小且对内存敏感的场景。
- Android 开发中推荐使用
SparseArray
替代HashMap<Integer, Object>
,以减少内存开销。
- 键是
- 不适合场景:
- 数据量特别大且插入/删除操作频繁时,因数组调整成本较高。
- 适合场景:
-
HashMap
- 适合场景:
- 键和值需要是任意类型的泛型数据。
- 数据量较大且插入/删除操作频繁的场景。
- 需要键的自定义哈希逻辑时。
- 不适合场景:
- 使用
Integer
作为键并对内存占用敏感时。
- 使用
- 适合场景:
4. 示例代码
使用 SparseArray
val sparseArray = SparseArray<String>()
sparseArray.put(1, "Apple")
sparseArray.put(2, "Banana")
println(sparseArray[1]) // 输出: Apple
使用 HashMap
val hashMap = HashMap<Int, String>()
hashMap[1] = "Apple"
hashMap[2] = "Banana"
println(hashMap[1]) // 输出: Apple
5. 总结
特性 | SparseArray | HashMap |
---|---|---|
键类型 | 仅支持 int | 任意类型 |
内存效率 | 高 | 相对较低 |
速度 | 小数据量、高内存敏感时快,例如recycler的缓存复用 | 插入/删除频繁或大数据量时快 |
灵活性 | 较低 | 高 |
- 如果键是
int
且内存效率优先,选择SparseArray
。 - 如果需要键的泛型支持或数据操作灵活性更重要,选择
HashMap
。
6.SparseArray的源码使用场景
HashMap的使用场景更多,毕竟是老方法了,例如bundle啊,SharedPreferences,fragment的缓存啊,还有我们的网络请求等等,下面举几个SparseArray的源码使用场景
1. View 的 ID 缓存
在 Android 的 View 系统中,View
类中使用了 SparseArray来存储 View 的状态信息。
相关源码:View#saveHierarchyState
和 View#restoreHierarchyState
SparseArray
被用来保存子视图的状态。- 每个子视图的 ID(
int
类型)作为键,对应的状态对象作为值
public void saveHierarchyState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
container.put(mID, onSaveInstanceState());
}
}
public void restoreHierarchyState(SparseArray<Parcelable> container) {
if (mID != NO_ID) {
Parcelable state = container.get(mID);
if (state != null) {
onRestoreInstanceState(state);
}
}
}
2. WindowManager 的 Token 管理
3. RecyclerView 的 ViewType 缓存,RecyclerView 使用 SparseArray来管理不同类型的 ViewHolder
。在RecyclerView.Recycler中,SparseArray用来存储 ViewType 和相应的 ViewHolder
。
4. Fragment 的保存与恢复,在 FragmentManager
中,SparseArray被用来保存 Fragment 的状态。