当我在Android中使用带有HashMap
键和数据值的Integer
时,我会在Eclipse中收到此消息:
Use new SparseIntArray(...) for better performance
现在问题是SparseIntArray()
没有实现Serializable
界面,并且无法与getSerializable()
中的putSerializable()
和onRestoreInstanceState()
一起使用。< / p>
使用SparseIntArray()
代替HashMap<Integer, Integer>
有多重要?
我应该解决使SparseIntArray
可序列化的麻烦吗? (我的第一个想法是创建一个实现Serializable
的包装器类,这是正确的方法吗?)
答案 0 :(得分:27)
1)使用
有多重要?SparseIntArray
代替HashMap
?
这取决于你如何使用它。但除非你试图代表这样的许多和/或大型“阵列”,否则差异不太可能显着。
请注意,Java SE没有任何稀疏数组类,通常不是问题。
2)我应该解决使
SparseIntArray
可序列化的麻烦吗? (我的第一个想法是创建一个实现Serializable
的包装类,这是正确的方法吗?)
见上文及以下。
实现包装听起来合理......如果你需要解决这个问题。另一种方法可能是声明SparseIntArray
的可序列化子类。建议使用自定义readObject
和writeObject
方法。
SparseIntArray
类(source code)使用一对int
数组来表示映射中的键和值,并使用二进制搜索进行查找。按键保持顺序没有“孔”,并使用二进制搜索执行查找。这意味着以下内容:
SparseIntArray
的内存使用量大约相当于同等HashMap
的10倍。这是由于各种因素的结合:
哈希表数组每个条目大约保留1个引用(取决于表的填充程度......),
键和值必须在Integer
中作为HashMap
个对象“加框”,并且
HashMap
中的每个条目都需要一个相当重的“节点”对象 - 标准实现中的4个字段。
(但是,如果以正确的方式创建Integer
个对象,可以通过Integer
类实例缓存的效果来减轻“装箱”开销。)
相比之下,稀疏版本需要2 * capacity
个4字节字。
查询(即get
)O(logN)
与O(1)
的{{1}}进行比较。
与HashMap
的{{1}}相比,O(N)
的随机插入次数为O(1)
。 (这是因为插入必须平均移动现有条目的一半,以便可以将新条目添加到数组中的正确位置。)
顺序插入(即以按键顺序递增)为HashMap
。
所以“哪个最好”显然取决于你所优化的内容,你如何使用数据结构,以及它将会有多大。
答案 1 :(得分:5)
使用HashMap<Integer, Integer>
的问题是每个键和值都需要加框。这种影响的范围可以是从大量垃圾生成和/或内存使用到系统的重负荷(更不用说装箱/拆箱值的轻微性能损失)。 (这些担忧也推动了几个第三方collection frameworks for primitives的发展。)
如果您认为SparseIntArray
的好处值得拥有,那么我认为您对包装类的方法是合理的。另一种方法是使其实现Parcelable
,它也可用于保存/恢复实例状态。