diff --git a/blogs/Java/口水话/集合源码.md b/blogs/Java/口水话/集合源码.md index 0ddb196..d11754d 100644 --- a/blogs/Java/口水话/集合源码.md +++ b/blogs/Java/口水话/集合源码.md @@ -15,6 +15,7 @@ 9. TreeSet 10. CopyOnWriteArrayList 11. ConcurrentHashMap +12. SparseArray #### ArrayList @@ -119,5 +120,15 @@ ConcurrentHashMap 在 put 时,在一个 for 死循环里面,也就是一定 ConcurrentHashMap 的 get 和 HashMap 基本无差。 -#### +#### SparseArray + +SparseArray 是 Android 中一种特有的数据结构,用来替代 HashMap 的。它里面有两个数组,一个是 int[] 数组存放 key,一个是 Object[] value 数组。也就是它的 key 只能为 int;在 put 时,会根据传入的 key 进行二分查找找到合适的插入位置,如果当前位置有值或者是 DELETED 节点,就直接覆盖,否则就需要拷贝数组后移一位,空出一个位置让其插入。如果数组满了但是还有 DELETED 节点,就需要调用 gc 方法,gc 方法所做的就是把 DELETED 节点后面的数前移,也就是真正的把 DELETED 节点删掉然后在插入,否则就只能扩容了。 + +调用 remove 时,并不会直接把 key 从 int[] 数组里面删掉,而是把当前 key 指向的 value 设置成 DELETED 节点,这样做是为了减少 int[] 数组的结构调整,结构调整就意味着数据拷贝。但是当我们调用 keyAt/valueAt 获取索引时,如果有 DELETED 节点就必须得调用 gc,不然获得的 index 肯定不对。 + +get 方法就比较简单了,二分查找获取 key 对应的索引 index,返回 values[index] 即可。 + +可以看到,SparseArray 比 HashMap 少了基本数据的自动装箱操作,而且不需要额外的结构体,单个元素存储成本低,在数据量小的情况下,随机访问的效率很高。但是缺点也是显而易见的,就是增删的效率比较低,在数据量比较大的时候,调用 gc 拷贝数组成本巨大。 + +除了 SparseArray,Android 还提供了 SparseIntArray(int:int)、SparseBooleanArray(int:boolean)、SparseLongArray(int:long) 等,其实就是把对应的 value 换成基本数据类型。