public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>//双向循环链表的头结点 private transient Entry<K,V> header; //accessOrder代表链表的排序方式;true为按照访问顺序,false为插入顺序。 private final boolean accessOrder;
//按指定的初始化容量和加载因子,生成一个空的LinkedHashMap,
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;//默认设为插入顺序
}
//按指定初始化容量,生成一个LinkedHashMap构造器;默认加载因子为0.75
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;//默认设为插入顺序
}
//生成一个LinkedHashMap构造器;默认加载因子为0.75,初始化容量为16
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap() {
super();
accessOrder = false;
}
//根据指定的map生成一个新的HashMap,负载因子使用默认值,初始容量大小为Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY)
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}
//按指定初始化容量,加载因子,链表的排序方式生成一个LinkedHashMap构造器
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
构造器首先都会调用父类也就是HashMap的构造器来初始化桶数组,而accessOrder之后会被初始化,
除了最后面的一个构造器允许指定accessOrder外,其他构造器都 默认将accessOrder置为了false 。public HashMap(int initialCapacity, float loadFactor) {
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
... ...
init();
}
HashMap构造器最后一步调用了一个init方法,而这个init方法在HashMap中是个空实现,没有任何代码。 /**
* 覆盖HashMap的init方法,在构造方法、Clone、readObject方法里会调用该方法
* 作用是生成一个双向链表头节点,初始化其前后节点引用
*/
@Override
void init() {
header = new Entry<>(-1, null, null, null);//初始化双向链表
header.before = header.after = header;//不光是双向链表,还是循环链表
}
//LinkedHashMap节点对象 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;//前后指针 //构造函数 Entry(int hash, K key, V value, HashMap.Entry<K,V> next) { super(hash, key, value, next); } //移除此节点,并修改前后的引用 private void remove() { before.after = after; after.before = before; } //将当前结点(this)插入到existingEntry结点前 private void addBefore(Entry<K,V> existingEntry) { after = existingEntry;//先获取existingEntry的前后节点 before = existingEntry.before; before.after = this;//双向指针,都需要修改 after.before = this; } /** * 在父类HashMap中的get,set方法会调用此方法recordAccess; * 在LinkedHashMap中,当按访问顺序排序时,该方法会将当前节点插入到链表尾部(头结点的前一个节点) * 否则不做任何事 */ void recordAccess(HashMap<K,V> m) { LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m; if (lm.accessOrder) {//当按访问顺序排序时 lm.modCount++; remove();//移除当前节点 addBefore(lm.header);//将当前节点插入到头结点前面 } } void recordRemoval(HashMap<K,V> m) { remove(); } }
public V put(K key, V value) {//HashMap的put方法
if (key == null)
return putForNullKey(value);
int hash = hash(key);
int i = indexFor(hash, table.length);
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;
}
}
... ...
}此外,在LinkedHashMap的get方法中,也会调用此方法: //根据指定key返回value:先得到entry结点,再返回其值;调用的是HashMap的getEntry方法
//与HashMap的区别是:当LinkedHashMap按访问顺序排序的时候,会将访问的当前节点移到链表尾部(头结点的前一个节点)
public V get(Object key) {
Entry<K,V> e = (Entry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
也就是说,只要涉及到访问结点,那么就会调用这个方法。 观察该方法的逻辑:
如果accessOrder为true,/** * 创建节点,插入到LinkedHashMap,该方法覆盖HashMap的addEntry方法 */ void addEntry(int hash, K key, V value, int bucketIndex) { super.addEntry(hash, key, value, bucketIndex); // eldest:头结点的下个节点header.after,存放于链表头部,是最不经常访问或第一个插入的节点, Entry<K,V> eldest = header.after; //有必要的情况下(如容量不够,具体看removeEldestEntry方法的实现,这里默认为false,不删除),可以先删除 if (removeEldestEntry(eldest)) { removeEntryForKey(eldest.key); } } /** * 创建节点,并将该节点插入到链表尾部 */ void createEntry(int hash, K key, V value, int bucketIndex) { HashMap.Entry<K,V> old = table[bucketIndex]; Entry<K,V> e = new Entry<>(hash, key, value, old); table[bucketIndex] = e; e.addBefore(header);//节点插入到链表尾部 size++; }createEntry方法会将键值对分别挂到桶数组和双向链表中。
//迭代器
private abstract class LinkedHashIterator<T> implements Iterator<T> {
Entry<K,V> nextEntry = header.after;
Entry<K,V> lastReturned = null;
//用于迭代期间快速失败行为
int expectedModCount = modCount;
//判断是否还有下个节点;当为头结点的时候说明没有下个节点即返回false
public boolean hasNext() {
return nextEntry != header;
}
//移除当前访问的节点
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
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();
Entry<K,V> e = lastReturned = nextEntry;
nextEntry = e.after;
return e;
}
}/**
* LinkedHashMap接口是的Map接口哈希表和链接列表的实现,
* 具有可预知的迭代顺序。这个实现类与HashMap不同之处在于其所有结点都之间以双链表进行维护。
* 此链表定义了迭代顺序,此顺序通常就是按键插入到映射中的顺序(插入顺序)。
* 注意:如果在映射中重新插入键,则插入顺序不受影响。
* 允许null元素;
* 增加了维护链接列表的开支,性能比HashMap稍逊;
* 此实现不是同步的,改为同步:
* Map m = Collections.synchronizedMap(new LinkedHashMap());
*
*/
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
private static final long serialVersionUID = 3801124242820219131L;
//双向循环链表的头结点
private transient Entry<K,V> header;
//accessOrder代表链表的排序方式;true为按照访问顺序,false为插入顺序。
private final boolean accessOrder;
//按指定的初始化容量和加载因子,生成一个空的LinkedHashMap,
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;//默认设为插入顺序
}
//按指定初始化容量,生成一个LinkedHashMap构造器;默认加载因子为0.75
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;//默认设为插入顺序
}
//生成一个LinkedHashMap构造器;默认加载因子为0.75,初始化容量为16
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap() {
super();
accessOrder = false;
}
//根据指定的map生成一个新的HashMap,负载因子使用默认值,初始容量大小为Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,DEFAULT_INITIAL_CAPACITY)
//默认将accessOrder设为false,按插入顺序排序.
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}
//按指定初始化容量,加载因子,链表的排序方式生成一个LinkedHashMap构造器
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
/**
* 覆盖HashMap的init方法,在构造方法、Clone、readObject方法里会调用该方法
* 作用是生成一个双向链表头节点,初始化其前后节点引用
*/
@Override
void init() {
header = new Entry<>(-1, null, null, null);//初始化双向链表
header.before = header.after = header;//不光是双向链表,还是循环链表
}
/**
* 覆盖HashMap的transfer方法,性能优化,这里遍历方式不采用HashMap的双重循环方式
* 而是直接通过双向链表遍历Map中的所有key-value映射
*/
@Override
void transfer(HashMap.Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;//获取新表大小
//遍历旧Map中的所有key-value
for (Entry<K,V> e = header.after; e != header; e = e.after) {
//看是否需要进行再哈希操作,需要的话就重新计算key的哈希值
if (rehash)
e.hash = (e.key == null) ? 0 : hash(e.key);
int index = indexFor(e.hash, newCapacity);//根据数组长度重新计算索引
e.next = newTable[index];//插入到链表表头
newTable[index] = e;//将e放到索引为i的数组处
}
}
//判断是否含有值value
//与HashMap不同地方在于是直接遍历链表进行查询获取,而不用计算key的hash值去寻找桶再遍历
public boolean containsValue(Object value) {
// Overridden to take advantage of faster iterator
if (value==null) {
for (Entry e = header.after; e != header; e = e.after)
if (e.value==null)
return true;
} else {
for (Entry e = header.after; e != header; e = e.after)
if (value.equals(e.value))
return true;
}
return false;
}
//根据指定key返回value:先得到entry结点,再返回其值;调用的是HashMap的getEntry方法
//与HashMap的区别是:当LinkedHashMap按访问顺序排序的时候,会将访问的当前节点移到链表尾部(头结点的前一个节点)
public V get(Object key) {
Entry<K,V> e = (Entry<K,V>)getEntry(key);
if (e == null)
return null;
e.recordAccess(this);
return e.value;
}
//清空链表:调用的父类clear方法
public void clear() {
super.clear();
header.before = header.after = header;
}
//LinkedHashMap节点对象
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;//前后指针
//构造函数
Entry(int hash, K key, V value, HashMap.Entry<K,V> next) {
super(hash, key, value, next);
}
//移除此节点,并修改前后的引用
private void remove() {
before.after = after;
after.before = before;
}
//将当前结点(this)插入到existingEntry结点前
private void addBefore(Entry<K,V> existingEntry) {
after = existingEntry;//先获取existingEntry的前后节点
before = existingEntry.before;
before.after = this;//双向指针,都需要修改
after.before = this;
}
/**
* 在父类HashMap中的get,set方法会调用此方法recordAccess;
* 在LinkedHashMap中,当按访问顺序排序时,该方法会将当前节点插入到链表尾部(头结点的前一个节点)
* 否则不做任何事
*/
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {//当按访问顺序排序时
lm.modCount++;
remove();//移除当前节点
addBefore(lm.header);//将当前节点插入到头结点前面
}
}
void recordRemoval(HashMap<K,V> m) {
remove();
}
}
//迭代器
private abstract class LinkedHashIterator<T> implements Iterator<T> {
Entry<K,V> nextEntry = header.after;
Entry<K,V> lastReturned = null;
//用于迭代期间快速失败行为
int expectedModCount = modCount;
//判断是否还有下个节点;当为头结点的时候说明没有下个节点即返回false
public boolean hasNext() {
return nextEntry != header;
}
//移除当前访问的节点
public void remove() {
if (lastReturned == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
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();
Entry<K,V> e = lastReturned = nextEntry;
nextEntry = e.after;
return e;
}
}
//key迭代器
private class KeyIterator extends LinkedHashIterator<K> {
public K next() { return nextEntry().getKey(); }
}
//value迭代器
private class ValueIterator extends LinkedHashIterator<V> {
public V next() { return nextEntry().value; }
}
//key-value迭代器
private class EntryIterator extends LinkedHashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() { return nextEntry(); }
}
// 返回不同的迭代器对象
Iterator<K> newKeyIterator() { return new KeyIterator(); }
Iterator<V> newValueIterator() { return new ValueIterator(); }
Iterator<Map.Entry<K,V>> newEntryIterator() { return new EntryIterator(); }
/**
* 创建节点,插入到LinkedHashMap,该方法覆盖HashMap的addEntry方法
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
super.addEntry(hash, key, value, bucketIndex);
// eldest:头结点的下个节点header.after,存放于链表头部,是最不经常访问或第一个插入的节点,
Entry<K,V> eldest = header.after;
//有必要的情况下(如容量不够,具体看removeEldestEntry方法的实现,这里默认为false,不删除),可以先删除
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
}
}
/**
* 创建节点,并将该节点插入到链表尾部
*/
void createEntry(int hash, K key, V value, int bucketIndex) {
HashMap.Entry<K,V> old = table[bucketIndex];
Entry<K,V> e = new Entry<>(hash, key, value, old);
table[bucketIndex] = e;
e.addBefore(header);//节点插入到链表尾部
size++;
}
/**
* 该方法在创建新节点的时候调用,
* 判断是否有必要删除链表头部的第一个节点(最不经常访问或最先插入的节点,由accessOrder决定)
*/
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
}【JDK源码阅读9-util】LinkedHashMap接口
原文:http://blog.csdn.net/noaman_wgs/article/details/53138604