LinkedHashMap
简介
LinkedHashMap是HashMap的子类;在HashMap的基础上又用双向链表来实现的;换句话说:LinkedHashMap的所有元素不仅满足HashMap的数据结构,同时满足LinkedList的结构,维护着这两套实现方式;
LinkedHashMap类主要是维护双向链表,其他的工作主要还是在HashMap中实现;
LinkedHashMapEntry
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
//这两个引用用来实现双向链表
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
主要变量
transient LinkedHashMapEntry<K,V> head;头结点,双链表中存在最久的节点;
transient LinkedHashMapEntry<K,V> tail;尾结点,链表中刚加入的节点;
final boolean accessOrder;是否根据访问顺序,改变双向链表的顺序;默认为false;实现LruCache算法的主要实现;
LinkedHashMap主要实现HashMap的三个空方法
// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }
put()方法
put()方法,还是调用HashMap的put()方法,主要区别在于putVal()中newNode()方法,会调用LinkedHashMap自己的newNode()方法;其他都一样,最后LikedHashMap方法实现了;
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
//1 调用LinkedHashMap的newNode()创建节点;
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k;
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
//2 如果key已存在,afterNodeAccess()在LinkedHashMap有具体的实现;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
//3 不存在的话,HashMap插入新节点,LinkedHashMap有具体的实现;
afterNodeInsertion(evict);
return null;
}
LinkedHashMap的newNode()方法;
//创建新节点,插入双链表尾后,并返回该节点;
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMapEntry<K,V> p =
new LinkedHashMapEntry<K,V>(hash, key, value, e);
linkNodeLast(p);
return p;
}
//在链表尾插入新节点;
private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
LinkedHashMapEntry<K,V> last = tail;
//将尾结点重新赋值;
tail = p;
//原尾结点为null,说明LinkedHashMap是空的,head也是null,将head也赋值;
if (last == null)
head = p;
//head节点不为null,相互引用:节点p的before引用指向last节点,last节点的after引用指向p节点;
else {
p.before = last;
last.after = p;
}
}
afterNodeAccess():如果根据访问顺序排序,并且访问的节点不是尾结点;将当前节点从链表中删除,再插入到尾结点后;
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMapEntry<K,V> last;
//如果根据访问顺序改变双向链表的顺序,并且访问的节点不是尾结点;
if (accessOrder && (last = tail) != e) {
//强转e得到节点p,并得到该节点的前一个节点b,后一个节点a;
LinkedHashMapEntry<K,V> p =
(LinkedHashMapEntry<K,V>)e, b = p.before, a = p.after;
//将节点p的after引用制null;
p.after = null;
//如果b为null,说明访问的节点是头结点,重新为头结点赋值;不是null,将b节点的after引用指向a节点;
if (b == null)
head = a;
else
b.after = a;
//正常情况下,由于判断过当前节点p不是尾结点,a就不会是null,将a的before引用指向b;
if (a != null)
a.before = b;
else
last = b;
//正常情况下,last节点不是null,将节点p添加到链表尾,last节点和p节点相互指向,p节点的before指向last节点,last节点的after引用指向p节点;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
//为尾结点重新赋值;
tail = p;
++modCount;
}
}
afterNodeInsertion():删除双向链表中最老的节点即头结点;默认情况下removeEldestEntry()返回false;LruCache类会重写,返回true;
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMapEntry<K,V> first;
//有put()方法可知evict为true;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
//调用HashMap的removeNode()
removeNode(hash(key), key, null, false, true);
}
}
get()方法
get():获取对应的值,并且如果是根据访问排序,在双向链表中先删除当前节点e,再插入到链表尾节点后;改变双向链表的顺序;
public V get(Object key) {
Node<K,V> e;
//调用HashMap的getNode()查找对应的节点,判读是否为null;不为null,
if ((e = getNode(hash(key), key)) == null)
return null;
//根据访问排序的话,在双向链表中先删除当前节点e,再插入到链表尾节点后;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
remove()方法
remove():完全调用HashMap的remove()方法,在删除之后调用afterNodeRemoval(),将当前节点从双向链表中删除;
void afterNodeRemoval(Node<K,V> e) { // unlink
LinkedHashMapEntry<K,V> p =
(LinkedHashMapEntry<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;
}
LruCache
内部使用LinkedHashMap作为成员变量存储元素;key,value都不能为null;根据LinkedHashMap的双链表和是否根据访问顺序排序特性来实现的;主要用于图片加载框架根据最近最少使用算法,删除不常用的图片,节约空间;
初始化
LruCache<String, String> lruCache = new LruCache<String, String>(10) {
//默认返回1;如果是Bitmap 得到对应的byte;
@Override
protected int sizeOf(String key, String value) {
//super.sizeOf(key,value);
return 2;
}
//值被替换或者被删除
@Override
protected void entryRemoved(boolean evicted, String key, String oldValue, String newValue) {
super.entryRemoved(evicted, key, oldValue, newValue);
}
};
put()方法:不存在key对应的节点,创建新的节点,加在双链表链尾;存在的话,将值替换;
public final V put(K key, V value) {
if (key == null || value == null) {
throw new NullPointerException("key == null || value == null");
}
V previous;
synchronized (this) {
putCount++;
//获取value的size,最后会调用sizeOf()方法,获取value的int值;并增加对应大小;
size += safeSizeOf(key, value);
//插入,如果存在key对应的节点,返回对应的值,否则返回null;
previous = map.put(key, value);
//如果不为null,减去对应的大小
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
//entryRemoved 为空方法,重写,手动释放对象value;
if (previous != null) {
entryRemoved(false, key, previous, value);
}
//计算当前最大size
trimToSize(maxSize);
return previous;
}
trimToSize()方法:put()方法之后,判断当前size是否大于maxSize,如果大于,删除最近最少使用的元素(即从双链表头删除头结点)
public void trimToSize(int maxSize) {
while (true) {
K key;
V value;
synchronized (this) {
if (size < 0 || (map.isEmpty() && size != 0)) {
throw new IllegalStateException(getClass().getName()
+ ".sizeOf() is reporting inconsistent results!");
}
if (size <= maxSize) {
break;
}
Map.Entry<K, V> toEvict = map.eldest();
if (toEvict == null) {
break;
}
key = toEvict.getKey();
value = toEvict.getValue();
map.remove(key);
size -= safeSizeOf(key, value);
evictionCount++;
}
entryRemoved(true, key, value, null);
}
}
get()方法:存在key对应的节点,直接返回对应的value;不存在,调用create(key)方法,该方法默认情况下,返回null;也可以创协create()方法,自己实现;
public final V get(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V mapValue;
synchronized (this) {
//根据key获取对应的value;
mapValue = map.get(key);
if (mapValue != null) {
hitCount++;
return mapValue;
}
missCount++;
}
//create过程异步
V createdValue = create(key);
if (createdValue == null) {
return null;
}
//create()返回的不为null
synchronized (this) {
createCount++;
//插入,并返回oldVaue;
mapValue = map.put(key, createdValue);
//不为空,在create()之前,又插入了其他value,则以上一次的value为准
if (mapValue != null) {
// There was a conflict so undo that last put
map.put(key, mapValue);
//增加size
} else {
size += safeSizeOf(key, createdValue);
}
}
if (mapValue != null) {
entryRemoved(false, key, createdValue, mapValue);
return mapValue;
} else {
trimToSize(maxSize);
return createdValue;
}
}
remove():存在key对应的节点,删除,并减去size;
public final V remove(K key) {
if (key == null) {
throw new NullPointerException("key == null");
}
V previous;
synchronized (this) {
previous = map.remove(key);
if (previous != null) {
size -= safeSizeOf(key, previous);
}
}
if (previous != null) {
entryRemoved(false, key, previous, null);
}
return previous;
}
所有的分析内容到此结束了。如有问题,请多指教,谢谢!