相对而言,linkedhashMap要比TreeMap更加重要
有一些逻辑以及LRU算法值得深究
在于与普通的哈希Map的比较时,特点是内部维护的双向链表,可以记录顺序(访问顺序,或插入顺序)
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
看类的声明,可以注意的是linkedhashMap是哈希Map的子类,也重写了在Hashmap里面的有一些有空方法体的方法
属性
//作为LinkedhashMap,用链表来维护一个顺序
private transient Entry<K,V> header;
//访问顺序,也就是涉及到以后用到的LRU,true:按照访问顺序,false:按照插入顺序
private final boolean accessOrder;
//继承了哈希Map的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;
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;
}
private void addBefore(Entry<K,V> existingEntry) {
after = existingEntry;
before = existingEntry.before;
before.after = this;
after.before = this;
}
//如果记录访问顺序,则将此元素记录在header之前
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();
}
}
</pre><pre name="code" class="java">
构造方法
//五个构造函数,总体来说是要有加载因子初始容量以及加载因子,并且默认关闭LRU
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap() {
super();
accessOrder = false;
}
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super(m);
accessOrder = false;
}
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
LinkedHashMap是基于双向链表的,而且属性中定了一个header节点
初始化
void init() {
header = new Entry<>(-1, null, null, null);
header.before = header.after = header;
}
transfer,旧数组到新数组
@Override
void transfer(HashMap.Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e = header.after; e != header; e = e.after) {
if (rehash)//如果需要重新哈希的话
e.hash = (e.key == null) ? 0 : hash(e.key);
int index = indexFor(e.hash, newCapacity);//计算位置
e.next = newTable[index];//倒序放置
newTable[index] = e;
}
}
//包含Value
public boolean containsValue(Object value) {
// Overridden to take advantage of faster iterator
if (value==null) {//找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;
}
get
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;
}
//getEntry,找到bucket,然后遍历
final Entry<K,V> getEntry(Object key) {
if (size == 0) {
return null;
}
int hash = (key == null) ? 0 : hash(key);
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
return e;
}
return null;
}
//获取哈希值
final int hash(Object k) {
int h = hashSeed;
if (0 != h && k instanceof String) {
return sun.misc.Hashing.stringHash32((String) k);
}
h ^= k.hashCode();
// This function ensures that hashCodes that differ only by
// constant multiples at each bit position have a bounded
// number of collisions (approximately 8 at default load factor).
h ^= (h >>> 20) ^ (h >>> 12);
return h ^ (h >>> 7) ^ (h >>> 4);
}
记录访问
void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {//如果true,记录访问顺序
lm.modCount++;
remove();
addBefore(lm.header); //根据LRU算法,使用过的最后被取出,也就是加在链表的最后,首先遍历取出来的是用的最少的
}
}
迭代器重写了,这里使用header开始迭代,顺序遍历,稍微看一下 expectedModCount,另外,这里只能删除,不提供别的方法
private abstract class LinkedHashIterator<T> implements Iterator<T> {
Entry<K,V> nextEntry = header.after;
Entry<K,V> lastReturned = null;
/**
* The modCount value that the iterator believes that the backing
* List should have. If this expectation is violated, the iterator
* has detected concurrent modification.
*/
int expectedModCount = modCount;
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;
}
}