当我在Android中使用具有Integer
键和数据值的HashMap
时,我在Eclipse中得到此消息:
Use new SparseIntArray(...) for better performance
现在的问题是SparseIntArray()
不实现Serializable
接口,不能与onRestoreInstanceState()
中的getSerializable()
和putSerializable()
一起使用。
使用
SparseIntArray()
代替HashMap<Integer, Integer>
有多重要?我应该经历使
SparseIntArray
可序列化的麻烦吗?(我的第一个想法是制作一个实现Serializable
的包装器类,这是正确的方法吗?)
1)用
SparseIntArray
代替HashMap
有多重要?
这取决于你如何使用它。但是,除非您尝试像这样表示许多和/或大型"数组",否则差异不太可能显着。
请注意,Java SE没有任何稀疏数组类,这通常不是问题。
2)我应该经历使
SparseIntArray
可序列化的麻烦吗?(我的第一个想法是制作一个实现Serializable
的包装器类,这是正确的方法吗?)
见上面和下面。
实现包装器听起来很合理…如果你非要这么麻烦的话。另一种方法可能是声明SparseIntArray
的可序列化子类。建议声明自定义readObject
和writeObject
方法。
SparseIntArray
类(源代码)使用一对int
数组来表示映射中的键和值,并使用二进制搜索来进行查找。键按顺序保存,没有"漏洞",并且使用二进制搜索执行查找。这意味着以下内容:
-
SparseIntArray
的内存使用量大约是同等HashMap
的10倍。这是由于以下几个因素造成的:-
哈希表数组每个条目大约有1个引用(取决于表有多满…),
-
键和值必须在
HashMap
中作为Integer
对象"装箱",并且 -
HashMap
中的每个条目都需要一个"node"对象,该对象在标准实现中具有相当重的权重- 4个字段。
(但是,如果您以正确的方式创建
Integer
对象,则可以通过Integer
类实例缓存的效果来减轻"装箱"开销。)相比之下,稀疏版本需要
2 * capacity
4字节字。 -
-
查找(即
get
)是O(logN)
与O(1)
对HashMap
的比较。 -
对于
HashMap
,随机插入是O(N)
,而O(1)
。(这是因为插入必须平均移动现有条目的一半,以便新条目可以添加到数组中的正确位置。) -
顺序插入(按键序升序)为
O(1)
所以"哪个是最好的"显然取决于你在优化什么,你如何使用数据结构,以及它将变得有多大。
使用HashMap<Integer, Integer>
的问题是每个键和值都需要装箱。这种影响的范围从零到由于产生大量垃圾和/或内存使用而给系统带来沉重的负载(更不用说装箱/拆箱值带来的轻微性能损失)。(这些问题也推动了几个第三方原语集合框架的开发。)
如果您认为SparseIntArray
的好处值得拥有,那么我认为您使用包装器类的方法是合理的。另一种方法是让它实现Parcelable
,它也可以用来保存/恢复实例状态。