前言:
前面學習總結了List的使用及效率對比,今天總結學習一下鍵值對映關係Map,順便學習一下Android中使用Map需要注意哪些,以及谷歌官方針對Android對Map做了哪些優化。
先了解下Map
Map 是一種把鍵物件和值物件對映的集合,它的每一個元素都包含一對鍵物件和值物件。 Map沒有繼承於Collection介面 從Map集合中檢索元素時,只要給出鍵物件,就會返回對應的值物件。
Map是一個介面,例項化Map可以採用下面的方式:
- HashMap //Map基於雜湊表的實現。插入和查詢“鍵值對”的開銷是固定的。可以通過構造器設定容量capacity和負載因子load factor,以調整容器的效能。
- LinkedHashMap //類似於HashMap,但是迭代遍歷它時,取得“鍵值對”的順序是其插入次序,或者是最近最少使用(LRU)的次序。只比HashMap慢一點。而在迭代訪問時發而更快,因為它使用連結串列維護內部次序。
- TreeMap //底層是二叉樹資料結構,執行緒不同步,可用於給Map集合中的鍵進行排序。
- HashTable //HashMap是Hashtable的輕量級實現,非執行緒安全的實現他們都實現了map介面,主要區別是HashMap鍵值可以為空null,效率可以高於Hashtable。
- ConcurrentHashMap //ConcurrentHashMap通常只被看做併發效率更高的Map,用來替換其他執行緒安全的Map容器,比如Hashtable和Collections.synchronizedMap。
- WeakHashMap //弱鍵(weak key)Map,Map中使用的物件也被允許釋放: 這是為解決特殊問題設計的。如果沒有map之外的引用指向某個“鍵”,則此“鍵”可以被垃圾收集器回收。
- IdentifyHashMap //使用==代替equals()對“鍵”作比較的hash map
- ArrayMap //ArrayMap是一個<key,value>對映的資料結構,它設計上更多的是考慮記憶體的優化,內部是使用兩個陣列進行資料儲存,一個陣列記錄key的hash值,另外一個陣列記錄Value值,它和SparseArray一樣,也會對key使用二分法進行從小到大排序,在新增、刪除、查詢資料的時候都是先使用二分查詢法得到相應的index,然後通過index來進行新增、查詢、刪除等操作,所以,應用場景和SparseArray的一樣,如果在資料量比較大的情況下,那麼它的效能將退化至少50%。
- SparseArray //SparseArray比HashMap更省記憶體,在某些條件下效能更好,主要是因為它避免了對key的自動裝箱(int轉為Integer型別),它內部則是通過兩個陣列來進行資料儲存的,一個儲存key,另外一個儲存value,為了優化效能,它內部對資料還採取了壓縮的方式來表示稀疏陣列的資料,從而節約記憶體空間。
Map的基本操作:
- Object put(Object key, Object value): 向集合中加入元素
- Object remove(Object key): 刪除與KEY相關的元素
- void putAll(Map t): 將來自特定映像的所有元素新增給該映像
- void clear():從映像中刪除所有對映
Map使用
這裡以最常用的HashMap為例
新增資料
Map<Integer, String> hashMap = new HashMap<>(); for (int i = 0; i < maxCount; i++) { hashMap.put(i, String.valueOf(i)); }
遍歷entrySet方式
long start = System.currentTimeMillis(); for (Map.Entry<Integer, String> entry : hashMap.entrySet()) { Integer key=entry.getKey(); String value=entry.getValue(); Log.i(TAG, "key: " + key +"value: "+value); } long end = System.currentTimeMillis(); Log.e(TAG, "for-each方式 cost time : " + (end - start));
entrySet迭代器遍歷方式
long start1 = System.currentTimeMillis(); Iterator<Map.Entry<Integer, String>> entries = hashMap.entrySet().iterator(); while (entries.hasNext()) { Map.Entry<Integer, String> entry = entries.next(); Integer key=entry.getKey(); String value=entry.getValue(); Log.i(TAG, "key: " + key +"value: "+value); } long end1 = System.currentTimeMillis(); Log.e(TAG, "entrySet iterator迭代器 cost time : " + (end1 - start1));
鍵找值遍歷
long end1 = System.currentTimeMillis(); Log.e(TAG, "iterator迭代器 cost time : " + (end1 - start1)); long start2 = System.currentTimeMillis(); for (Integer key : hashMap.keySet()) { String value = hashMap.get(key); Log.i(TAG, "key: " + key +"value: "+value); } long end2 = System.currentTimeMillis(); Log.e(TAG, "鍵找值遍歷 cost time : " + (end2 - start2));
keySet迭代器遍歷
long start3 = System.currentTimeMillis(); Iterator<Integer> iterator=hashMap.keySet().iterator(); while (iterator.hasNext()) { Integer key=iterator.next(); String value=hashMap.get(key); Log.i(TAG, "key: " + key +"value: "+value); } long end3 = System.currentTimeMillis(); Log.e(TAG, "keySet iterator迭代器 cost time : " + (end3 - start3));
上述四種情況執行結果如下:
總結:
主要重新熟悉一下Map這種資料結構,以及更好的在以後的程式設計中選擇更合適的方式來進行key-value儲存。