您的位置:首页 > 编程语言 > Java开发

Java集合(13)--LinkedHashMap源码分析

2015-08-17 23:02 645 查看
HashMap使用哈希表来存储数据,并用拉链法来处理冲突。LinkedHashMap继承自HashMap,同时自身有一个链表,使用链表存储数据,不存在冲突。

LinkedList和LinkedHashMap一样使用一个双向循环链表,但LinkedList存储的是简单的数据,并不是“键值对”。

LinkedList和LinkedHashMap都可以维护内容的顺序,但HashMap不维护顺序。

public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>


HashMap的init方法没有实现,但是LinkedHaqshMap已经对其实现:

void init() {
//初始化一个Entry类型的header
header = new Entry<K,V>(-1, null, null, null);
header.before = header.after = header;
}


在LinkedHashMap中多了一个accessOrder变量,他表示迭代时候的一个顺序,若为true,则按照读取顺序排序(读得越多在链表的越后面,读得越少在链表的越前面,LRU,最近最少使用),若为false则按照插入顺序排序.从LinkedHaqshMap的前4个构造方法可以看出,accessOrder默认为false,故按照插入顺序进行排序。

void recordAccess(HashMap<K,V> m) {
LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
if (lm.accessOrder) {
lm.modCount++;
remove();
addBefore(lm.header);
}
}


在LRU算法中,最少使用的页面被先换出,最近使用的很可能以后还会使用。

他判断accessOrder属性,若为true,则执行一个叫做LRU的算法,将刚访问的entry移除,然后加到header前面,这样迭代的时候会优先迭代最近频繁访问的entry(不是链表头),从而就改变了迭代的顺序。

void addEntry(int hash, K key, V value, int bucketIndex) {
createEntry(hash, key, value, bucketIndex);
Entry<K,V> eldest = header.after;
if (removeEldestEntry(eldest)) {
removeEntryForKey(eldest.key);
} else {
if (size >= threshold)
resize(2 * table.length);
}
}


protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
//始终返回的是false
return false;
}


启发:若希望将Map当做Cache来使用,并且限制大小,只需继承LinkedHashMap并重写removeEldestEntry(Entry<K,V> eldest)方法,像这样:

private static final int MAX_ENTRIES = 100;
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > MAX_ENTRIES;
}


实现最近被使用(LRU)缓存:

import java.util.LinkedHashMap;
import java.util.Map;

public LRUCache<K, V> extends LinkedHashMap<K, V> {
private int cacheSize;

public LRUCache(int cacheSize) {
super(16, 0.75, true);//排序策略
this.cacheSize = cacheSize;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: