LinkedHashMap
目录
LinkedHashMap
说明:HashMap可以保存 k=v 的结构,但不保证迭代器的顺序
为了提供有顺序的hashmap,jdk提供此类
默认使用的插入的顺序
可以通过构造器设置为按照访问顺序
继承关系
- 继承HashMap ,因此已经具备所有Map功能,只需要自定义需要的特殊功能
构造器
-
LinkedHashMap(int, float) 设定初始大小和负载因子
-
LinkedHashMap(int) 设定初始大小.负载因子默认(0.75)
-
LinkedHashMap() 初始大小使用16(使用父类HashMap设定)
-
LinkedHashMap(Map<? extends K, ? extends V>) 使用默认构造器,并将指定map中数据初始化保存到此map中
-
[特殊]LinkedHashMap(int, float, boolean) 设置顺序为读/写?
默认设置,顺序使用写入顺序,使用此构造器new LinkedHashMap(16,0.75,true) 可设置为按照访问的顺序
field
- transient LinkedHashMap.Entry<K,V> head; 第一个节点
- transient LinkedHashMap.Entry<K,V> tail; 最后一个节点
- accessOrder : boolean 插入/访问顺序
方法
containsValue(Object) 检测指定值是否在map中
// linkedHashmap 重写了此方法,但没有重写 containsKey
// 因为key有hash优化,而value没有,只能迭代检查.
// hashmap 中node 要双循环, 这里则是单循环,所有做了重写
public boolean containsValue(Object value) {
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
V v = e.value;
if (v == value || (value != null && value.equals(v)))
return true;
}
return false;
}
// hashmap.containsValue
Node<K,V>[] tab; V v;
if ((tab = table) != null && size > 0) {
for (Node<K,V> e : tab) {
for (; e != null; e = e.next) {
if ((v = e.value) == value ||
(value != null && value.equals(v)))
return true;
}
}
}
return false;
get
// 需要在获取到key之后,根据设置,移动节点位置到最后(如果设置为访问顺序)
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
afterNodeAccess
// 访问之后.将被访问节点放到最后
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
afterNodeInsertion(boolean)
// put之后将node节点放到最后
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
afterNodeRemoval
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}
newNode(int, K, V, Node<K, V>)
LinkedHashMap 没有在put方法中处理tail问题,
而是把tail问题放在了newNode中
也就是map中如果要放入新的节点,必然要创建新的node,只要把新建的node作为tail就能保证tail问题
newTreeNode(int, K, V, Node<K, V>)
处理 treeNode 情况 同理: replacementNode replacementTreeNode方法
迭代器 LinkedHashIterator
// 从head 开始迭代,以next为标志abstract class LinkedHashIterator { LinkedHashMap.Entry<K,V> next; LinkedHashMap.Entry<K,V> current; int expectedModCount; LinkedHashIterator() { next = head; expectedModCount = modCount; current = null; } public final boolean hasNext() { return next != null; } final LinkedHashMap.Entry<K,V> nextNode() { LinkedHashMap.Entry<K,V> e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); current = e; next = e.after; return e; } public final void remove() { Node<K,V> p = current; if (p == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; removeNode(p.hash, p.key, null, false, false); expectedModCount = modCount; } }