1?Map
Map 定義了鍵值存儲的數據操作的接口, 主要用于鍵值的存儲,使用鍵可以得到值,并且不允許重復的鍵,值可以重復,可以起到數據的快速獲取的目的。Java 1.5 后有了 concurrent 包,因此處理 java.utils 里面有 Map 的實現外,concurrent 包中也增加了同步 Map 的實現。
1.1?java.util 中的 Map 實現
1.1.1?HashMap
1. HashMap 繼承自AbstractMap, 實現了 Map、Serializable, Cloneable 接口。
2. HashMap是單向鏈表數組的存儲結構(拉鏈法),根據 Key 的 HashCode 值運算后作為數組的 index 存儲數據,根據 key 可以直接獲取它的值,具有很快的訪問速度,遍歷時,取得數據的順序時完全隨機的。
3. HashMap 只允許一條記錄的鍵為 Null;
4. HashMap 不支持多線程的同步,即任意時刻可以有多個線程同時寫 HashMap,可能會導致數據的不一致。如果需要同步,可以使用 Collections 的 synchronizedMap 方法使 HashMap 具有同步的能力, 或者使用 ConcurrentHashMap。
5. 不能使用 get() 方法返回 null值判斷是否包含是否包含該鍵,而應該使用 constainsKey() 方法來判斷。
6. 默認的長度為16, 擴充是按照 2 的指數倍進行擴充,這一點可以看下 HashMap 的 resize() 方法。
final Node[] resize() {
????Node[] oldTab = table;
????int oldCap = (oldTab == null) ? 0 : oldTab.length;
????int oldThr = threshold;
????int newCap, newThr = 0;
????if (oldCap > 0)
????{
????????if (oldCap >= MAXIMUM_CAPACITY) // 長度超過最大限制時不再擴充
????????{
????????????threshold = Integer.MAX_VALUE;
????????????return oldTab;
????????} else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
????????????// 原 size 擴充一倍小于最大限制且舊的 size 大于等于默認大小時,
????????????//設置新的大小原來 threshold 一倍, 那么 threshold 在使用無參構造函數時是怎么設置值呢?在本函數中,繼續向下看
????????????newThr = oldThr << 1; // double threshold
????????} else if (oldThr > 0)
????????????// 默認 threshold 為 0, 默認的初始化方法,第一次存放數據時該代碼不會執行
????????????newCap = oldThr;
? ? ? ? ?else // zero initial threshold signifies using defaults
????????{
????????????//此處為默認的初始化的 Map ,第一次存放數據執行的地方,為設置 size 為默認的大小即:16,
? ? ? ? ? ? //下次調整大小的為默認的 factor (0.75) * 16 。
????????????newCap = DEFAULT_INITIAL_CAPACITY;
????????????newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
????????????}
? ? ?if (newThr == 0)
????{
????????????float ft = (float)newCap * loadFactor;
????????????newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE);
? ? ?}
????????threshold = newThr;
????????// 。。。。。。。。
????????return newTab;
}
7. 計算 Key 的 hash() 值
static final int hash(Objectkey)
?{
????int h;
?????return(key ==null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
8. hashMap 實際存儲的是一個單項鏈表的數組;
9. 新增元素時,key 為 null 的值直接放到數組的首位,否則使用 hash()計算的值,與當前的存儲數組的長度length-1 后有 key 的 hash 做 按位與(&)的操作或許下標,如果該 index 下已經存在項,則創建新的 node,并做存儲的鏈表的開始位置,將 next 指向想一個元素,否則,存儲新的節點,下一個元素為 null。
10. get() 元素時, 使用 key 的 hashcode 運算后獲取到 index, 使用 index 獲取鏈表后進行遍歷, 找到 key 對應的值;
11. HashMap 提供了 keySet() 方法集獲取 key 的 set 集合, values() 方法獲取值的 collection, entrySet() 方法返回了 entry 的 set 集合。
1.1.2?Hashtable
1. Hashtable 繼承自 java.util.Dictionary 抽象類,實現了 Map,Cloneable, Serializable 接口;
2. Hashtable 存儲結構與 HashMap 一樣,使用的單向鏈表數組,但是,hastable 不允許 key 和 value 為 null;
3. key 的 hashCode 是使用的 key 本身的 hashkey;
4. Hashtable 是線程安全,它使用 synchronized 對public 的函數加鎖實現到了同步;
5. Hashtable 默認大小是 11,這個在其默認的構造函數里面可以看到:
public Hashtable()
{
????this(11, 0.75f);
}
當需要擴充是,Hashtable 是擴充為原來大小的 1 倍 + 1
protected void rehash()
{
????int oldCapacity= table.length;
????Entry[] oldMap= table;
????// overflow-conscious code
????int newCapacity= (oldCapacity << 1) + 1;
????if(newCapacity - MAX_ARRAY_SIZE > 0)
????????{
????????????????if(oldCapacity == MAX_ARRAY_SIZE)
????????????????// Keep running with MAX_ARRAY_SIZE buckets
????????????????return;? ? ? ?
????????newCapacity = MAX_ARRAY_SIZE;? ?
????????}?
????? .........
}
1.1.3?LinkedHashMap
LinkedHashMap 繼承自 HashMap,實現了 Map 接口。LinedHashMap 存入元素默認是按照插入的順序保存。遍歷LinkedHashMap時,先得到的記錄肯定是先插入的。也可以在構造時用帶參數,按照應用次數排序。在遍歷的時候會比HashMap慢,不過有種情況例外,當HashMap容量很大,實際數據較少時,遍歷起來可能會比 LinkedHashMap慢,因為LinkedHashMap的遍歷速度只和實際數據有關,和容量無關,而HashMap的遍歷速度和他的容量有關。
LinkedHashMap 存儲元素 Entry 在 HashMap.Node 的基礎上增加了如下的before 和 after,使之變成了雙向的鏈表結構,源碼如下:
static class Entry?extends HashMap.Node?
{
????Entry?before,after;
????Entry(int hash,K key,V value,Node?next)
????{
????????super(hash, key, value, next);? ?
????}
}
1.1.4?TreeMap
1. TreeMap 繼承自 AbstractMap, 實現了 SortedMap 的接口。實現了NavigableMap接口,意味著它支持一系列的導航方法。比如返回有序的key集合。
2. 基于紅黑樹實現。TreeMap沒有調優選項,因為該樹總處于平衡狀態。
3. TreeMap 會按照 key 的存儲順序進行排序,默認使用使用字典升序排列, 可以自己實現 Comparator 來自定義排序規則。
TreeMap 提供構造函數如下:
// 默認構造函數。使用該構造函數,TreeMap中的元素按照自然排序進行排列。
TreeMap()
// 創建的TreeMap包含
Map TreeMap(Map copyFrom)
// 指定Tree的比較器
TreeMap(Comparator?comparator)
// 創建的TreeSet包含copyFrom
TreeMap(SortedMap copyFrom)
關于詳細的介紹,大家可以去看這里?http://www.cnblogs.com/skywang12345/p/3310928.html?, 介紹的非常詳細,同時對紅黑樹也相應的文章進行介紹。
1.1.5?WeakHashMap
WeakHashMap 實現了 Map 接口,繼承自 AbstractMap, 與 HashMap 的用法基本相同,不同的是它使用弱引用作為存儲內部數據的方案,當系統內存不夠的時候,垃圾收集器會自動的清除沒有在其他任何地方被引用的鍵值對。在使用 WeakHashMap 進行大量數據的進行緩存時,如果超過 JVM 的內存大小,會先對引用的數據進行 GC,然后再存放新的數據。可以看看在執行 put(K k, V v) 方法時,會執行 getTable 的方法
public V put(K key, V value)
{
????Object k = maskNull(key);
????int h = hash(k);
????Entry[] tab = getTable();
????int i = indexFor(h, tab.length);
????……
?return null;
}
而 getTable() 的方法會執行 expungeStaleEntries(), 移除沒有引用的鍵值對。
private void expungeStaleEntries()
{
????for (Object x; (x = queue.poll()) != null; )
????{
????synchronized (queue)
????{
????????????@SuppressWarnings("unchecked")
????????????Entry e = (Entry) x;
????????int i = indexFor(e.hash, table.length);
????????Entry prev = table[i];
????????Entry p = prev;
????????while (p != null)
????????{
????????????????Entry next = p.next;
????????????????if (p == e)
????????????????{
????????????????????????if (prev == e)
????????????????????????????????table[i] = next;
????????????????????????else prev.next = next;
????????????????????????// Must not null out e.next;
????????????????????????// stale entries may be in use by a HashIterator
????????????????????????e.value = null; // Help GC
????????????????????????size--; break;
????????????????}
????????????????prev = p;
????????????????p = next;
????????????}
????????}
????}
}
這就是有人覺得使用 WeakHashMap 不靠譜的地方吧。
1.2?java.util.concurrent
concurrent 包是java1.5 后添加的,包含許多線程安全、測試良好、高性能的并發構建塊。
1.2.1?ConcurrentHashMap
ConcurrentHashMap 與 HashMap 非常相似,
ConcurrentHashMap 在線程安全的基礎上提供了更好的寫并發能力。
繼承自 AbstractMap,實現了 ConcurrentMap 接口。
基本的操作與 HashMap 是一致的,一些關鍵的屬性增加了線程同步的控制。
1.2.2?ConcurrentSkipListMap
首先簡單的介紹下 SkipList 跳表,跳表也是使用的一種擴展的單向鏈表的數據結構,普通的單向鏈表是一種線性結構,前一個節點指向后一個節點,而跳表則是前一個節點可能執行后一個和后續的其他節點,以空間換時間,提高了查找的效率。
ConcurrentSkipListMap 提供了一種線程安全的排序的映射表。內部是SkipList(跳表)結構實現,在理論上能夠 O(log(n)) 時間內完成查找、插入、刪除等操作。
2?參考資料
http://blog.csdn.net/io_field/article/details/53281884
http://www.importnew.com/22007.html