一、基本结构对比
// ArrayMap的基本结构
class ArrayMap<K, V> {
// 用于存储hash值的数组
private var mHashes: IntArray
// 用于存储key和value的数组,长度是mHashes的2倍
private var mArray: Array<Any?>
}
// SparseArray的基本结构
class SparseArray<V> {
// 用于存储key的数组(必须是int类型)
private var mKeys: IntArray
// 用于存储value的数组
private var mValues: Array<Any?>
}
二、主要区别
- 键的类型限制
// ArrayMap可以使用任意类型作为key
val arrayMap = ArrayMap<String, String>() // key可以是任意类型
arrayMap["key"] = "value"
// SparseArray只能使用int作为key
val sparseArray = SparseArray<String>() // key只能是int
sparseArray.put(1, "value")
- 内存占用
class MemoryExample {
fun memoryComparison() {
// ArrayMap需要额外的内存来存储key的hash值
val arrayMap = ArrayMap<Int, String>() // 需要三个数组空间
// SparseArray直接使用int作为key,不需要额外的hash计算
val sparseArray = SparseArray<String>() // 只需要两个数组空间
}
}
- 查找方式
class SearchExample {
fun searchComparison() {
// ArrayMap使用二分查找hash值
val arrayMap = ArrayMap<String, String>()
arrayMap["key"] = "value"
// 查找时:1.计算key的hash值 2.二分查找hash数组 3.获取值
// SparseArray直接对key进行二分查找
val sparseArray = SparseArray<String>()
sparseArray.put(1, "value")
// 查找时:直接二分查找key数组
}
}
三、性能对比
class PerformanceTest {
fun comparePerformance() {
val count = 1000
// 1. ArrayMap测试
val arrayMap = ArrayMap<Int, String>()
val arrayMapTime = measureTimeMillis {
for (i in 0 until count) {
arrayMap[i] = "value$i"
}
for (i in 0 until count) {
arrayMap[i]
}
}
// 2. SparseArray测试
val sparseArray = SparseArray<String>()
val sparseArrayTime = measureTimeMillis {
for (i in 0 until count) {
sparseArray.put(i, "value$i")
}
for (i in 0 until count) {
sparseArray.get(i)
}
}
println("ArrayMap time: $arrayMapTime")
println("SparseArray time: $sparseArrayTime")
}
}
四、使用场景
- ArrayMap适用场景
// 1. 需要使用非int类型作为key时
val userMap = ArrayMap<String, User>()
userMap["user1"] = User()
// 2. 数据量较小(几百个元素以内)时
val smallDataMap = ArrayMap<Any, Any>()
// 3. 内存敏感但又不能使用SparseArray时
class MemorySensitiveClass {
private val map = ArrayMap<String, Int>(10) // 指定初始容量
}
- SparseArray适用场景
// 1. key为int类型时
val viewCache = SparseArray<View>()
viewCache.put(R.id.button, button)
// 2. 对性能要求较高时
class HighPerformanceCache {
private val cache = SparseArray<Data>()
fun getData(id: Int): Data? {
return cache.get(id)
}
}
// 3. 需要频繁增删改查时
class FrequentOperations {
private val dataStore = SparseArray<String>()
fun updateData(id: Int, value: String) {
dataStore.put(id, value)
}
}
五、内部实现差异
class InternalDifference {
fun explainDifference() {
// 1. ArrayMap的put操作
val arrayMap = ArrayMap<String, Int>()
arrayMap["key"] = 1
// 内部流程:
// 1.计算key的hashCode
// 2.二分查找hash数组定位位置
// 3.将hash值存入hash数组
// 4.将key和value存入对象数组
// 2. SparseArray的put操作
val sparseArray = SparseArray<Int>()
sparseArray.put(1, 1)
// 内部流程:
// 1.直接二分查找key数组定位位置
// 2.将key和value分别存入两个数组
}
}
六、选择建议
class UsageGuide {
fun chooseContainer() {
// 1. 数据量小,key类型多样
val smallMap = ArrayMap<Any, Any>()
// 2. key为int,注重性能
val idCache = SparseArray<Data>()
// 3. 数据量大,不考虑内存
val largeMap = HashMap<String, String>()
// 4. key为基本类型的特殊情况
val intMap = SparseArray<String>() // key为int
val longMap = SparseLongArray() // key为long
val booleanMap = SparseBooleanArray() // key为boolean
}
}
主要区别总结:
- ArrayMap可以使用任意类型作为key,而SparseArray只能用int
- SparseArray内存占用更少,因为不需要存储hash值
- SparseArray在key为int时性能更好,因为避免了hash计算
- ArrayMap更通用,但内存占用稍大
- 两者都适合数据量较小的场景(几百个元素以内)
选择建议:
- 如果key是int类型,优先使用SparseArray
- 如果key是其他类型,且数据量小,使用ArrayMap
- 如果数据量大,考虑使用HashMap