稀疏数组 vs 哈希映射创建稀疏数组添加或更新项目移除项目整型键的查找值循环访问项目

2022-08-31 06:24:19

我可以想到几个原因,为什么带有整数键的s比s好得多:HashMapSparseArray

  1. Android文档说“它通常比传统文档慢”。SparseArrayHashMap
  2. 如果您使用 s 而不是 s 编写代码,则您的代码将与 Map 的其他实现一起使用,并且您将能够使用为 Maps 设计的所有 Java API。HashMapSparseArray
  3. 如果你使用s而不是s来编写代码,你的代码将在非Android项目中工作。HashMapSparseArray
  4. 地图覆盖,而不会。equals()hashCode()SparseArray

然而,每当我尝试在Android项目中使用带有整数键时,IntelliJ告诉我应该使用一个。我发现这真的很难理解。有谁知道使用s的任何令人信服的理由吗?HashMapSparseArraySparseArray


答案 1

稀疏数组可用于在键是基元类型时替换 HashMap。对于不同的键/值类型,有一些变体,即使并非所有变体都是公开的。

好处是:

  • 免分配
  • 没有拳击

缺点:

  • 通常较慢,不适用于大型集合
  • 它们不适用于非Android项目

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个元素的vs示例:SparseIntArrayHashMap<Integer, Integer>

SparseIntArray:

class SparseIntArray {
    int[] keys;
    int[] values;
    int size;
}

类 = 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;
}

类 = 12 + 8 * 4 = 48 字节
条目 = 32 + 16 + 16 = 64 字节
数组 = 20 + 1000 * 64 = 64024 字节
总数 = 64,136 字节

资料来源:Romain Guy的Android Memories,来自第90张幻灯片。

上面的数字是 JVM 在堆上分配的内存量(以字节为单位)。它们可能因使用的特定 JVM 而异。

该软件包包含一些用于高级操作的有用方法,例如使用 检查对象的大小。java.lang.instrumentgetObjectSize(Object objectToSize)

更多信息可从官方 Oracle 文档中获取

类 = 12 字节 + (n 个实例变量) * 4 字节
数组 = 20 字节 + (n 个元素) * (元素大小)
条目 = 32 字节 + (第 1 个元素大小) + (第 2 个元素大小)


答案 2

我来到这里只是为了一个如何使用SparseArray的例子。这是对此的补充答案。

创建稀疏数组

SparseArray<String> sparseArray = new SparseArray<>();

将整数映射到某个整数,因此您可以在上面的示例中用任何其他 .如果要将整数映射到整数,请使用 SparseIntArraySparseArrayObjectStringObject

添加或更新项目

使用 put(或 append)将元素添加到数组中。

sparseArray.put(10, "horse");
sparseArray.put(3, "cow");
sparseArray.put(1, "camel");
sparseArray.put(99, "sheep");
sparseArray.put(30, "goat");
sparseArray.put(17, "pig");

请注意,密钥不需要按顺序排列。这还可用于更改特定键处的值。intint

移除项目

使用删除(或删除)从数组中删除元素。

sparseArray.remove(17); // "pig" removed

该参数是整数键。int

整型键的查找值

使用 get 获取某个整数键的值。

String someAnimal = sparseArray.get(99);  // "sheep"
String anotherAnimal = sparseArray.get(200); // null

你可以使用 get(int key, E valueIfKeyNotFound) 如果你想避免获取丢失的键。null

循环访问项目

可以使用 keyAtvalueAt 某些索引来遍历集合,因为 维护一个与键不同的单独索引。SparseArrayint

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

请注意,键按升序值排序,而不是按添加顺序排序。