我可以想到为什么带有整数键的HashMap
比SparseArray
s好得多的原因有几个:
SparseArray
的Android文档说"它通常比传统的HashMap
"慢。HashMap
而不是SparseArray
编写代码,您的代码将与Map的其他实现一起使用,您将能够使用为地图设计的所有Java API。HashMap
而不是SparseArray
编写代码,您的代码将在非Android项目中运行。equals()
和hashCode()
,而SparseArray
则不会。然而,每当我尝试在Android项目中使用带有整数键的HashMap
时,IntelliJ告诉我应该使用SparseArray
。我觉得这很难理解。有没有人知道使用SparseArray
的任何令人信服的理由?
答案 0 :(得分:206)
SparseArray
可用于替换HashMap
。
对于不同的键/值类型,存在一些变体,即使并非所有键/值都是公开可用的。
好处是:
缺点:
HashMap
可以替换为以下内容:
SparseArray <Integer, Object>
SparseBooleanArray <Integer, Boolean>
SparseIntArray <Integer, Integer>
SparseLongArray <Integer, Long>
LongSparseArray <Long, Object>
LongSparseLongArray <Long, Long> //this is not a public class
//but can be copied from Android source code
就记忆而言,以下是1000个元素的SparseIntArray
与HashMap<Integer, Integer>
的示例:
SparseIntArray
:
class SparseIntArray {
int[] keys;
int[] values;
int size;
}
Class = 12 + 3 * 4 = 24字节
数组= 20 + 1000 * 4 = 4024字节
总计= 8,072字节
HashMap
:
class HashMap<K, V> {
Entry<K, V>[] table;
Entry<K, V> forNull;
int size;
int modCount;
int threshold;
Set<K> keys
Set<Entry<K, V>> entries;
Collection<V> values;
}
Class = 12 + 8 * 4 = 48字节
进入= 32 + 16 + 16 = 64字节
数组= 20 + 1000 * 64 = 64024字节
总计= 64,136字节
来自幻灯片90的Android Memories by Romain Guy。
上面的数字是JVM在堆上分配的内存量(以字节为单位)。 它们可能因所使用的特定JVM而异。
java.lang.instrument
包中包含一些有用的高级操作方法,例如使用getObjectSize(Object objectToSize)
检查对象的大小。
官方Oracle documentation提供了额外信息。
Class = 12字节+(n个实例变量)* 4个字节
数组= 20个字节+(n个元素)*(元素大小)
Entry = 32字节+(第一元素大小)+(第二元素大小)
答案 1 :(得分:24)
我来到这里只是想要一个如何使用SparseArray
的例子。这是对此的补充答案。
SparseArray<String> sparseArray = new SparseArray<>();
SparseArray
将整数映射到某些Object
,因此您可以将上述示例中的String
替换为任何其他Object
。如果要将整数映射到整数,请使用SparseIntArray
。
sparseArray.put(10, "horse");
sparseArray.put(3, "cow");
sparseArray.put(1, "camel");
sparseArray.put(99, "sheep");
sparseArray.put(30, "goat");
sparseArray.put(17, "pig");
请注意,int
键不需要按顺序排列。这也可用于更改特定int
键的值。
sparseArray.remove(17); // "pig" removed
int
参数是整数键。
使用get
获取某个整数键的值。
String someAnimal = sparseArray.get(99); // "sheep"
String anotherAnimal = sparseArray.get(200); // null
如果您想避免null
丢失密钥,可以使用get(int key, E valueIfKeyNotFound)
。
您可以使用keyAt
和valueAt
某些索引来循环收集集合,因为SparseArray
维护了一个与int
密钥不同的单独索引。
int size = sparseArray.size();
for (int i = 0; i < size; i++) {
int key = sparseArray.keyAt(i);
String value = sparseArray.valueAt(i);
Log.i("TAG", "key: " + key + " value: " + value);
}
// key: 1 value: camel
// key: 3 value: cow
// key: 10 value: horse
// key: 30 value: goat
// key: 99 value: sheep
请注意,键按升序排序,而不是按照添加顺序排序。
答案 2 :(得分:17)
然而每当我尝试在android中使用带有整数键的HashMap时 项目,intelliJ告诉我,我应该使用SparseArray。
这只是来自documentation稀疏数组的警告:
它的目的是比使用HashMap更高效 将整数映射到对象
SparseArray
比使用常规HashMap更强内存效率,这不允许数组中的多个间隙不像HashMap。没有什么可担心的,如果您不想担心设备的内存分配,可以使用传统的HashMap。
答案 3 :(得分:10)
经过一些谷歌搜索后,我尝试将一些信息添加到已经发布的答案中:
Isaac Taylor对SparseArrays和Hashmaps进行了性能比较。他说那是
Hashmap和SparseArray对于数据结构非常相似 尺寸低于1,000
和
当大小增加到10,000标记[...] Hashmap时 在添加对象时具有更高的性能,而SparseArray具有 检索对象时的更高性能。 [...]大小为100,000 [...]时,Hashmap会很快失去性能
对Edgblog的比较表明SparseArray需要比HashMap少得多的内存,因为密钥较小(int vs Integer),事实是
HashMap.Entry实例必须跟踪对的引用 键,值和下一个条目。此外,它还需要存储 条目的哈希值为int。
作为结论,我会说如果要在地图中存储大量数据,差异可能很重要。否则,只需忽略警告。
答案 4 :(得分:9)
Java中的稀疏数组是将键映射到值的数据结构。与Map相同,但实现方式不同:
Map在内部表示为列表数组,其中这些列表中的每个元素都是键值对。键和值都是对象实例。
稀疏数组简单地由两个数组组成:(基元)键的数组和(对象)值的数组。这些数组索引可能存在间隙,因此称为“稀疏”数组。
SparseArray的主要兴趣在于它通过使用基元而不是对象作为关键来节省内存。
答案 5 :(得分:2)
SparseArray的android文档说“通常是 慢于传统的HashMap“。
是的,没错。但是当你只有10或20个项目时,性能差异应该是微不足道的。
如果您使用HashMaps而不是SparseArrays编写代码 将与Map的其他实现一起使用,您将能够 使用为Maps
设计的所有Java API
我认为我们通常只使用HashMap
来搜索与某个键相关联的值,而SparseArray
确实很擅长这一点。
如果您使用HashMaps而不是SparseArrays编写代码 将在非Android项目中工作。
SparseArray的源代码非常简单易懂,因此您只需花费很少精力将其移至其他平台(通过简单的COPY&amp; Paste)。
映射覆盖equals()和hashCode(),而SparseArray不是
我能说的是(对于大多数开发者)谁在乎?
SparseArray
的另一个重要方面是它只使用数组来存储HashMap
使用Entry
时的所有元素,因此SparseArray
的成本显着低于HashMap
1}},请参阅this
答案 6 :(得分:1)
不幸的是编译器发出警告。我猜HashMap已被过度用于存储项目。
SparseArrays有它们的位置。鉴于他们使用二进制搜索算法在数组中查找值,您必须考虑您正在做什么。二进制搜索是O(log n),而哈希查找是O(1)。这并不一定意味着对于给定的数据集,二进制搜索较慢。但是,随着条目数量的增加,哈希表的功能将取代。因此,条目数量少,可能比使用HashMap更好的注释。
HashMap只能与哈希一样好,也可能受到加载因子的影响(我认为在以后的版本中,它们会忽略加载因子,因此可以更好地优化)。他们还添加了一个二级哈希,以确保哈希是好的。 SparseArray也适用于相对较少的条目(&lt; 100)。
我建议如果你需要一个哈希表,并希望更好的内存使用原始整数(没有自动装箱)等,试试trove。 (http://trove.starlight-systems.com - LGPL许可证)。 (与他们的图书馆没有任何隶属关系)
通过简化的多dex建筑,我们甚至不需要根据您的需要重新包装。 (特洛伊有很多课程)