MapClassDiagram
Map
(1)维护key-value 之间的映射,key不可以重复。
(2)提供三个视图:EntryKey,Values,EntrySet
(3)map自身不能做为key,put到自身的map中。但可以作为value。
(4)使用Entry来存放Key-Value
AbstractMap
(1)Clone:浅拷贝
(2)两个Map.Entry实现SimpleEntry,SimpleImmutableEntry(不可改变Entry)
Map实现类中都有自己Map.Entry实现。
HashMap
(1)存储结构:数组+链表(哈希表+链表处理冲突),允许key为Null,浅拷贝
(2)Default Size=16,Default Load Factor=0.75. 可以在构造map时指定。
(3)transient Entry[], transient Size. 自己拥有WriteObject和ReadObject方法。
(4)capacity永远是2的倍数。
(5)HashMap.Entry 存放四个值:
final K key;
V value;
Entry<K,V> next;
final int hash;
(6)Null Key:
如果Key 为Null 则key的hash值为0,进而index值为0。
(7)get过程:参数key
public V get(Object key) { if (key == null) //如果key为Null, 则在table[0]处进行查找。 return getForNullKey(); //如果key不为Null int hash = hash(key.hashCode()); //计算hash值和index, 在table[index]下进行查找。 for (Entry<K,V> e = table[indexFor(hash, table.length)]; e != null; e = e.next) { Object k; //比较hash值和key值,如果都相同则返回value。 if (e.hash == hash && ((k = e.key) == key || key.equals(k))) return e.value; } return null; }
private V getForNullKey() { //key 为Null, index 为0. for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) return e.value; } return null; }
(8)put过程:
public V put(K key, V value) { if (key == null) //如果key为Null return putForNullKey(value); //key 不为Null //计算hash,index int hash = hash(key.hashCode()); int i = indexFor(hash, table.length); //如果key已经存在则进行替换,返回之前的值。 for (Entry<K,V> e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } //如果key不存在,则添加。 modCount++; addEntry(hash, key, value, i); return null; } //put for Null key private V putForNullKey(V value) { //在table[0]的位置进行查找,存在更新值,不存在则添加。 for (Entry<K,V> e = table[0]; e != null; e = e.next) { if (e.key == null) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(0, null, value, 0); return null; } //添加使用“头插法”,将新插入Entry放在table[index]的位置。 void addEntry(int hash, K key, V value, int bucketIndex) { Entry<K,V> e = table[bucketIndex]; table[bucketIndex] = new Entry<K,V>(hash, key, value, e); if (size++ >= threshold) //如果size大于阀值,扩充table容量。 resize(2 * table.length); }
(9)Resize 过程
void resize(int newCapacity) { Entry[] oldTable = table; int oldCapacity = oldTable.length; //如果当前capacity已经是最大值,则将阀值改为最大值 if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } //创建新的table Entry[] newTable = new Entry[newCapacity]; //将原table中的值重新定位到新的table当中。 transfer(newTable); //更新现有引用,并计算阀值 table = newTable; threshold = (int)(newCapacity * loadFactor); } void transfer(Entry[] newTable) { Entry[] src = table; int newCapacity = newTable.length; for (int j = 0; j < src.length; j++) { Entry<K,V> e = src[j]; if (e != null) { src[j] = null; do { Entry<K,V> next = e.next; //重新定位index int i = indexFor(e.hash, newCapacity); //头插法插入新table e.next = newTable[i]; newTable[i] = e; e = next; } while (e != null); } } }
(10)Remove 过程
final Entry<K,V> removeEntryForKey(Object key) { //计算hash值和index int hash = (key == null) ? 0 : hash(key.hashCode()); int i = indexFor(hash, table.length); //找到要遍历查找的链表头元素 Entry<K,V> prev = table[i]; Entry<K,V> e = prev; while (e != null) { Entry<K,V> next = e.next; Object k; if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { modCount++; size--; if (prev == e) //如果删除的是头元素 table[i] = next; else //从链表中删除 prev.next = next; e.recordRemoval(this); return e; } //向后推移 prev = e; e = next; } return e; }
LinkedHashMap
LinkedHashMap在HashMap的基础上进行封装,将entry按照插入顺序链接起来,形成双向链表。
(1) LinkedHashMap.Entry 继承了HashMap.Entry 添加了before和after指针(指向LinkedHashMap.entry)。
private static class Entry<K,V> extends HashMap.Entry<K,V> { // These fields comprise the doubly linked list used for iteration. Entry<K,V> before, after; //给HashMap.Entry赋值。 Entry(int hash, K key, V value, HashMap.Entry<K,V> next) { super(hash, key, value, next); } }
(2)accessOrder:来确定按照何种顺序进行访问。
a) access-order: from least-recently accessed to most-recently. 适合使用LRU算法。(按照最近访问顺序,从最近最少使用到最近最多使用)
void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) { lm.modCount++; //从链表中移除 remove(); //添加到链表尾部。 addBefore(lm.header); }}
b) insertion-order:插入顺序。
(3)重写了transfer方法,是的resize的性能提高。
void transfer(HashMap.Entry[] newTable) { int newCapacity = newTable.length; //使用链表进行迭代。 for (Entry<K,V> e = header.after; e != header; e = e.after) { int index = indexFor(e.hash, newCapacity); e.next = newTable[index]; newTable[index] = e; } }
同理其它在HashMap中需要迭代的地方都使用链表进行迭代。如containsValue,KeyIterator, ValueIterator, EntryIterator等。
(4)添加Entry的时候会调用addBefore(header)方法,建立链表关系。
private void addBefore(Entry<K,V> existingEntry) { //实际existing就是指header after = existingEntry; before = existingEntry.before; before.after = this; after.before = this; }
(5)删除时同样会删除链表关系。
private void remove() { before.after = after; after.before = before; }
浙公网安备 33010602011771号