集合----LinkedHashMap
LinkedHashMap提供了Map应有的所有算法,允许为null。
与HashMap一样,初始容量和加载因子对LinkedHashMap影响很大,但是它便利时初始容量是不受影响的。
LinkedHashMap是非同步的。
access-ordered结构性的修改是会影响遍历的顺序的。在insertion-ordered这种条件下,修改已有的key的value,不是结构性修改。但在access-ordered这种条件下,使用get方法就已经是结构性修改了。
LindeHashMap的域
static class Entry<K,V> extends HashMap.Node<K,V> {//继承HashMap的Node节点,它是双向链表,包含前置指针和后置指针
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;
final boolean accessOrder;
LinkedHashMap重写的方法
//初始化散列表和双向链表
void reinitialize() {
super.reinitialize();
head = tail = null;
}
//创建一个普通entry,将entry插入到双向链表的末尾,最后返回entry
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
- 在构建新节点时,构建的是LinkedHashMap.Entry不再是Node。
LinkedHashMap的构造方法
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);//调用的是HashMap的构造方法
accessOrder = false;//默认是插入顺序
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
LinkedHashMap的方法
put方法
LinkedHashMap继承这HashMap,LinkedHashMap没有重写HashMap的put方法,所以LinkedHashMap的put方法和HashMap是一样的,在putVal()方法中,在创建节点newNode()过程,调用的是LinkedHashMap重写的方法。
get方法
public V get(Object key) {
Node<K,V> e;
//调用HashMap定义的方法获取对应的节点
if ((e = getNode(hash(key), key)) == null)
return null;
//如果是访问顺序的话,把该节点放到链表最后面
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
//将节点放到链表最后
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;
}
}
remove方法
在LinkedHashMap中没有重写remove方法,它调用的是父类HashMap的remove()方法,在LinkedHashMap中重写的是afterNodeRemoval(Node<K,V> e)这个方法。
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;
}
遍历的方法
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
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;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
初始容量对遍历没有影响,因为遍历的是LinkedHashMap内部维护的一个双向链表,而不是散列表。