簡體   English   中英

SparseArray vs HashMap

[英]SparseArray vs HashMap

我可以想到為什么帶有整數鍵的HashMapSparseArray更好的幾個原因:

  1. SparseArray的Android文檔說“它通常比傳統的HashMap慢”。
  2. 如果使用HashMap而不是SparseArray編寫代碼,您的代碼將與Map的其他實現一起使用,您將能夠使用為Maps設計的所有Java API。
  3. 如果你使用HashMap而不是SparseArray編寫代碼,你的代碼將在非android項目中工作。
  4. 映射會覆蓋equals()hashCode()SparseArray則不會。

然而,每當我嘗試在Android項目中使用帶有整數鍵的HashMap時,IntelliJ告訴我應該使用SparseArray 我覺得這很難理解。 有沒有人知道使用SparseArray的任何令人信服的理由?

當密鑰是基本類型時, SparseArray可用於替換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 

在內存方面,這里有一個SparseIntArrayHashMap<Integer, Integer>的示例,用於1000個元素:

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字節
Entry = 32 + 16 + 16 = 64字節
數組= 20 + 1000 * 64 = 64024字節
總計= 64,136字節

資料來源: Romain Guy的Android Memories,來自幻燈片90。

上面的數字是JVM在堆上分配的內存量(以字節為單位)。 它們可能因所使用的特定JVM而異。

java.lang.instrument包包含一些有用的高級操作方法,例如使用getObjectSize(Object objectToSize)檢查對象的大小。

可從Oracle官方文檔中獲取更多信息。

Class = 12字節+(n個實例變量)* 4個字節
數組= 20個字節+(n個元素)*(元素大小)
Entry = 32字節+(第一個元素大小)+(第二個元素大小)

我來到這里只是想要一個如何使用SparseArray的例子。 這是一個補充答案。

創建一個SparseArray

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

SparseArray將整數映射到某個Object ,因此您可以將上面示例中的String替換為任何其他Object 如果要將整數映射到整數,請使用SparseIntArray

添加或更新項目

使用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");

請注意, int鍵不需要按順序排列。 這也可以用於更改特定int鍵的值。

刪除項目

使用remove (或delete )從數組中刪除元素。

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

int參數是整數鍵。

查找int鍵的值

使用get獲取某個整數鍵的值。

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

如果要避免為缺失鍵獲取null ,可以使用get(int key, E valueIfKeyNotFound)

迭代這些項目

您可以使用keyAtvalueAt一些索引循環遍歷集合,因為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

請注意,鍵按升序排序,而不是按添加順序排序。

然而,每當我嘗試在android項目中使用帶有整數鍵的HashMap時,intelliJ告訴我應該使用SparseArray。

它只是來自稀疏數組的這個文檔的警告:

與使用HashMap將整數映射到對象相比,它的內存效率更高

與使用常規HashMap相比, SparseArray 內存效率高,不允許數組中的多個間隙不像HashMap。 沒有什么可擔心的,如果您不想擔心設備的內存分配,可以使用傳統的HashMap。

Java中的稀疏數組是將鍵映射到值的數據結構。 與Map相同,但實現方式不同:

  1. Map在內部表示為列表數組,其中這些列表中的每個元素都是鍵值對。 鍵和值都是對象實例。

  2. 稀疏數組簡單地由兩個數組組成:(基元)鍵的數組和(對象)值的數組。 這些數組索引可能存在間隙,因此稱為“稀疏”數組。

SparseArray的主要興趣在於它通過使用基元而不是對象作為關鍵來節省內存。

在谷歌搜索后,我嘗試將一些信息添加到已經發布的答案中:

Isaac Taylor對SparseArrays和Hashmaps進行了性能比較。 他說

對於1,000以下的數據結構大小,Hashmap和SparseArray非常相似

當大小增加到10,000標記時,Hashmap在添加對象時具有更高的性能,而SparseArray在檢索對象時具有更高的性能。 [...]大小為100,000 [...],Hashmap很快失去了性能

Edgblog的比較表明SparseArray需要比HashMap少得多的內存,因為密鑰較小(int vs Integer),而且事實是

HashMap.Entry實例必須跟蹤密鑰,值和下一個條目的引用。 另外,它還需要將條目的哈希值存儲為int。

作為結論,我會說,如果要在Map中存儲大量數據,差異可能很重要。 否則,只需忽略警告。

SparseArray的android文檔說“它通常比傳統的HashMap慢”。

是的這是對的。 但是當你只有10或20個項目時,性能差異應該是微不足道的。

如果使用HashMaps而不是SparseArrays編寫代碼,您的代碼將與Map的其他實現一起使用,您將能夠使用為Maps設計的所有Java API

我想我們通常只使用HashMap來搜索與鍵相關聯的值,而SparseArray確實很擅長這一點。

如果你使用HashMaps而不是SparseArrays編寫代碼,你的代碼將在非android項目中工作。

SparseArray的源代碼非常簡單易懂,因此您只需花費很少精力將其移動到其他平台(通過簡單的COPY和Paste)。

映射會覆蓋equals()和hashCode(),而SparseArray則不會

我只能說,(對大多數開發者)誰在乎?

SparseArray另一個重要方面是它只使用數組存儲所有元素,而HashMap使用Entry ,因此SparseArray成本比HashMap要少得多,請參閱此內容

不幸的是,編譯器發出警告。 我猜HashMap已被過度用於存儲項目。

SparseArrays有它們的位置。 鑒於他們使用二進制搜索算法在數組中查找值,您必須考慮您正在做什么。 二進制搜索是O(log n),而哈希查找是O(1)。 這並不一定意味着對於給定的數據集,二進制搜索較慢。 但是,隨着條目數量的增加,哈希表的功能將取代。 因此,少數條目可以等於並且可能比使用HashMap更好的注釋。

HashMap只能和哈希一樣好,也可以受到加載因子的影響(我認為在以后的版本中它們會忽略加載因子,因此可以更好地優化)。 他們還添加了一個二級哈希,以確保哈希是好的。 SparseArray也適用於相對較少的條目(<100)。

我建議如果你需要一個哈希表,並希望更好的內存使用原始整數(沒有自動裝箱)等,試試trove。 http://trove.starlight-systems.com - LGPL許可證)。 (與他們的圖書館沒有隸屬關系)

通過簡化的多dex建築,我們甚至不需要根據您的需要重新包裝。 (有很多課程)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM