在分析LinkedHashMap的源码以前先看一下LinkedHashMap的继承关系算法
经过上述继承关系能够看到,LinkedHashMap继承自HashMap,也就是具备HashMap的全部功能,而后再看看源码中的注释:数组
从注释中能够了解到,LinkedHashMap本身维护了一个双向链表,确切地说是一个双向循环链表,下面看一下双向循环链表安全
private static final long serialVersionUID = 3801124242820219131L;
//双链表的头结点
private transient LinkedHashMapEntry<K,V> header;
//双链表的迭代顺序,true表示按照访问的顺序,false表示插入的顺序
private final boolean accessOrder;复制代码
private static class LinkedHashMapEntry<K,V> extends HashMapEntry<K,V> {
// before为指向上一个节点的指针,after为指向下一个节点的指针
LinkedHashMapEntry<K,V> before, after;
//构造方法
LinkedHashMapEntry(int hash, K key, V value, HashMapEntry<K,V> next) {
super(hash, key, value, next);
}
//删除某个节点,也就是将当前节点的前一个节点跟后一个节点链接在一块儿
private void remove() {
//将上一个节点的尾指针指向下个节点
before.after = after;
//将下一个节点的头指针指向上一个节点
after.before = before;
}
//在某个节点以前插入一个节点,结合上面你的示意图比较好理解
private void addBefore(LinkedHashMapEntry<K,V> existingEntry) {
//将当前节点的after指针指向插图的节点
after = existingEntry;
//将当前节点的before指针指向existingEntry的上一个节点
before = existingEntry.before;
//before的尾节点指向当前节点
before.after = this;
//after的头结点指向当前节点
after.before = this;
}
//当一个已经存在的entry被get方法调用或者被set方法修改的时候此方法被父类(HashMap)调用,若是access-ordered为true,那么entry就会被移动到链表的尾部,不然不做处理。
void recordAccess(HashMap<K,V> m) {
//将HashMap强转成LinkedHashMap
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {
//若是accessOrder为true
lm.modCount++;
//先移除此entry
remove();
//将lm添加到队尾
addBefore(lm.header);
}
}
void recordRemoval(HashMap<K,V> m) {
remove();
}
}复制代码
LinkedHashMap的构造方法其实就是间接调用了HashMap的构造方法,而后给迭代标志位accessOrder一个false,也就是默认按照插入的顺序进行排序,比较简单bash
public LinkedHashMap() {
super();
accessOrder = false;
}复制代码
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}复制代码
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}复制代码
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}复制代码
public V get(Object key) {
LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
if (e == null)
return null;
//调用了get方法,就会将当前的entry放到链表的尾部,删除的时候就会最后删除
e.recordAccess(this);
return e.value;
}复制代码
经过查找发现LinkedHashMap并无复写Get方法,只是复写了addEntry多线程
void addEntry(int hash, K key, V value, int bucketIndex) {
//这个是Android作的一些修改,略微不一样于Java的SDK
LinkedHashMapEntry<K,V> eldest = header.after;
if (eldest != header) {
boolean removeEldest;
size++;
try {
//判断是否移除最近最少使用的Entry
removeEldest = removeEldestEntry(eldest);
} finally {
size--;
}
if (removeEldest) {
//根据返回值是否移除最近最少使用的entry
removeEntryForKey(eldest.key);
}
}
//调用父类的addEntry
super.addEntry(hash, key, value, bucketIndex);
}复制代码
//removeEldestEntry的返回值老是false,这个须要根据实际状况来复写,默认不移除并发
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}复制代码
public boolean containsValue(Object value) {
if (value == null)
return containsNullValue();
HashMapEntry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (HashMapEntry e = tab[i] ; e != null ; e = e.next)
if (value.equals(e.value))
return true;
return false;
}
private boolean containsNullValue() {
HashMapEntry[] tab = table;
for (int i = 0; i < tab.length ; i++)
for (HashMapEntry e = tab[i] ; e != null ; e = e.next)
if (e.value == null)
return true;
return false;
}复制代码
public boolean containsValue(Object value) {
// Overridden to take advantage of faster iterator
if (value==null) {
for (LinkedHashMapEntry e = header.after; e != header; e = e.after)
if (e.value==null)
return true;
} else {
for (LinkedHashMapEntry e = header.after; e != header; e = e.after)
if (value.equals(e.value))
return true;
}
return false;
}复制代码
仔细观察一下发现,LinkedHashMap用双链表自身的特性去遍历了整个链表,从而替换了HashMap中的循环遍历,这个是由于链表遍历的效率更高。ide
void transfer(HashMapEntry[] newTable) {
int newCapacity = newTable.length;
for (HashMapEntry<K, V> e : table) {
while (null != e) {
HashMapEntry<K, V> next = e.next;
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
}
}
}复制代码
@Override
void transfer(HashMapEntry[] newTable) {
int newCapacity = newTable.length;
for (LinkedHashMapEntry<K,V> e = header.after; e != header; e = e.after) {
int index = indexFor(e.hash, newCapacity);
e.next = newTable[index];
newTable[index] = e;
}
}复制代码
其实跟containsValue同样,用自身的链表特性进行迭代,提升效率ui
插入一个元素,默认是插入到队列的尾部this
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMapEntry<K,V> old = table[bucketIndex];
LinkedHashMapEntry<K,V> e = new LinkedHashMapEntry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);
size++;
}复制代码
LinkedHashMap彻底重写了HashMap的迭代器spa
private abstract class LinkedHashIterator<T> implements Iterator<T> {
//默认的下个entry指的是链表的第1个entry节点
LinkedHashMapEntry<K,V> nextEntry = header.after;
//上一次返回的entry,也就是当前节点
LinkedHashMapEntry<K,V> lastReturned = null;
//用来判断是不是多线程并发
int expectedModCount = modCount;
//是否还有下一个节点
public boolean hasNext() {
return nextEntry != header;
}
//移除掉某个entry节点
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
//移除当前entry节点
LinkedHashMap.this.remove(lastReturned.key);
lastReturned = null;
expectedModCount = modCount;
}
Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (nextEntry == header)
throw new NoSuchElementException();
LinkedHashMapEntry<K,V> e = lastReturned = nextEntry;
//返回当前节点的下一个节点
nextEntry = e.after;
return e;
}
}复制代码
private class KeyIterator extends LinkedHashIterator<K> {
public K next() { return nextEntry().getKey(); }
}复制代码
private class ValueIterator extends LinkedHashIterator<V> {
public V next() { return nextEntry().getValue(); }
}复制代码
private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() { return nextEntry(); }
}复制代码
Key,Value,Entry分别复写了next方法
到此为止,基本上已经分析完成了LinkedHashedMap源码的基本分析,主要仍是须要对双向循环链表比较熟悉,它自己实际上也只是循环链表的一个实现类