前言:
在我们学习一个新技术,新东西之前,我们往往会先考虑到以下几个问题:
- SparseArray是什么?
- SparseArray有什么优点和缺点?
- SparseArray是如何实现这些优点?
- SparseArray为什么会有这些缺点?
通过了解这些问题,我们才能做出合理的判断,来决定是否需要继续学习,以及如何正确的使用。这篇博客,将会照着这个思路,来浅析SparryArray。【SparryArray缩写成 SA】
一,SparseArray是什么 ?
SparseArray是一个类似于HashMap的集合类,其有别于HashMap的主要有以下几点:
- key是基本的数据类型int。【优缺参半,限制了key的类型】
- key,没有拆装箱操作,因为key是基本数据类型。【优点,减少内存占用】
- key与value的映射,没有中间商赚差价。即HashMap里面,为了解决HashMap的冲突问题,额外创建的TreeNode,当出现Hash冲突时,key与value的映射,还需要走一层链表遍历查找。【优点,逻辑更简单,没有创建额外的对象(链表)】
- 集合操作的时间更慢,因为增删查改的时间复杂度,HashMap为O(1)【最理想时为O(1),最不理想时是O(n),JDK8后改用红黑树,时间优化为O(log(n))】,而SparryArray为O(log2n)。O(log2n)标准的折半查找的时间复杂度,而其内部实现,也正是用了折半查找的算法。因此,当集合的量超过1千条时,建议还是用回HashMap。【优缺参半,实现逻辑更简单,速度更慢】
- 数据结构不同,SparseArray,内部是两个数组,即数组+数组的形式【附图1所示】,分别用来存储key和value,它们的下标是一一对应的。而HashMap,则是数组+链表的形式【附图2所示】。【同4】
- Android only, Java标准集合类库里面,没有这个类。其它Java项目,普遍不支持。但不排除有专门导入这个类文件的Java项目。【缺点】
二,为什么选择SparseArray?
通过第一部分,我们了解到,SparseArray是一个集合类,以及它相对于HashMap的几个区别点。通过区别点,我们了解到,当你需要使用HashMap来存储,以int类型为key,且数量较少[低于1k]时,使用SparseArray来代替HashMap,可以避免HashMap的自动拆装箱操作,以及键值对的两个数组的映射关系,一一对应(下标一致),不用像HashMap一样,依赖链表来存储value,计算出key的下标后,还得再匹配一遍链表,才能获取到key对应的value。因此,我们应该只在恰当的业务需求下,使用SparseArray来代表HashMap。否则,得不偿失。
三,SparseArray的实现原理是什么?
SparseArray的内部实现原理,很简单。其内部结构是由两个数组组成,分别用来存储key和value。但是,key和value虽然分别存储在两个不同的数组里面,但他们所在的下标是一致的。 比方说,我往SparseArray, 存入一组数据:300和abc。假设,300被存到key数组的下标为8的地方。那么,abc一定是被存到value数组的下标为8的地方。这样,在查找时,只要求得key或value的下标,就可以知道另一个的下标。
那么,问题来了。这个下标是怎么得出来的?那得从put(int,T)方法讲起,也是时候,放点代码,提提神了。来人,上代码!
public void put(int key, E value) {
int i = ContainerHelpers.binarySearch(mKeys, mSize, key);
if (i >= 0) {
mValues[i] = value;
} else {
i = ~i;
if (i < mSize && mValues[i] == DELETED) {
mKeys[i] = key;
mValues[i] = value;
return;
}
if (mGarbage && mSize >= mKeys.length) {
gc();
// Search again because indices may have changed.
i = ~ContainerHelpers.binarySearch(mKeys, mSize, key);
}
mKeys = GrowingArrayUtils.insert(mKeys

本文深入解析SparseArray集合类,探讨其与HashMap的区别,包括key类型、内存占用、逻辑复杂度及性能对比。通过代码示例,详细阐述SparseArray的内部实现原理,包括增删查改操作及垃圾回收机制。
最低0.47元/天 解锁文章
1055





