[英]SparseArray vs HashMap
我可以想到為什么帶有整數鍵的HashMap
比SparseArray
更好的幾個原因:
SparseArray
的Android文檔說“它通常比傳統的HashMap
慢”。 HashMap
而不是SparseArray
編寫代碼,您的代碼將與Map的其他實現一起使用,您將能夠使用為Maps設計的所有Java API。 HashMap
而不是SparseArray
編寫代碼,你的代碼將在非android項目中工作。 equals()
和hashCode()
而SparseArray
則不會。 然而,每當我嘗試在Android項目中使用帶有整數鍵的HashMap
時,IntelliJ告訴我應該使用SparseArray
。 我覺得這很難理解。 有沒有人知道使用SparseArray
的任何令人信服的理由?
當密鑰是基本類型時, 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
在內存方面,這里有一個SparseIntArray
與HashMap<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)
檢查對象的大小。
Class = 12字節+(n個實例變量)* 4個字節
數組= 20個字節+(n個元素)*(元素大小)
Entry = 32字節+(第一個元素大小)+(第二個元素大小)
我來到這里只是想要一個如何使用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
請注意,鍵按升序排序,而不是按添加順序排序。
然而,每當我嘗試在android項目中使用帶有整數鍵的HashMap時,intelliJ告訴我應該使用SparseArray。
它只是來自稀疏數組的這個文檔的警告:
與使用HashMap將整數映射到對象相比,它的內存效率更高
與使用常規HashMap相比, SparseArray
內存效率高,不允許數組中的多個間隙不像HashMap。 沒有什么可擔心的,如果您不想擔心設備的內存分配,可以使用傳統的HashMap。
Java中的稀疏數組是將鍵映射到值的數據結構。 與Map相同,但實現方式不同:
Map在內部表示為列表數組,其中這些列表中的每個元素都是鍵值對。 鍵和值都是對象實例。
稀疏數組簡單地由兩個數組組成:(基元)鍵的數組和(對象)值的數組。 這些數組索引可能存在間隙,因此稱為“稀疏”數組。
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.