首先我们来看看LinkedHashMap的一些特性。通常我们新建一个LinkedHashMap,是这样创建的 new LinkedHashMap<K,V>();这是LinkedHashMap的默认构造方法,这样新建的LinkedHashMap中 元素的排序方式是put 时进去的顺序以后顺序也不会改变。而LinkedHashMap还提供了另外一种构造方法
new LinkedHashMap<>(initialCapacity, loadFactor, accessOrder) ,三个参数分别为,LinkedHashMap初始容量(记住不是大小而是容量,容量表示有能力容纳多少个元素,而大小是当前map包含的元素个数,当然初始化的时候大小为0)、LinkedHashMap的加载因子一般我们设为 0.75f (加载因子的意思是,当map的大小超过 initialCapacity*loadFactor,map就会扩容)、accessOrder为true表示map会根据访问顺序来调整元素内部顺序。
LinkedHashMap的get()方法除了返回元素之外还可以把被访问的元素放到链表的底端,所以最近访问的元素将会在最下面(链表的底端)。下面给一个例子
public class Test {
public static void main(String[] args) {
Map<String,String> map = new LinkedHashMap<String,String>(5, 0.75f, true);
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
map.put("d", "4");
map.put("e", "5");
//输出map的默认顺序
for(Map.Entry<String, String> mEntry : map.entrySet()){
System.out.println(mEntry.getKey()+","+mEntry.getValue());
}
map.get("b");
map.get("d");
System.out.println();
//输出map因为访问 导致的顺序改变后的顺序
for(Map.Entry<String, String> mEntry : map.entrySet()){
System.out.println(mEntry.getKey()+","+mEntry.getValue());
}
}
}
输出结果:
a,1
b,2
c,3
d,4
e,5
a,1
c,3
e,5
b,2
d,4
我们可以看到 最近访问的两个元素跑到了最下面(链表的底端)。
下面来实现一个类继承LinkedHashMap来实现缓存 (注意 linkedHashMap 不是线程安全的,所有其实现的缓存也不是线程安全的)
1 新建一个LRUCache类实现缓存
public class LRUCache<K,V> extends LinkedHashMap<K,V>{
private int capacity = 16;//默认最大缓存数为16
public LRUCache(){
super(16,0.75f,true);
}
/**
* @param capacity 设定缓存数
*/
public LRUCache(int capacity){
super(16,0.75f,true);
this.capacity = capacity;
}
/**
* 我们提供的删除缓存策略是:
* 当 LinkedHashMap的大小大于 我们设定的容量时 移除链表最顶端元素
*/
@Override
public boolean removeEldestEntry(Map.Entry<K, V> entry){
//重写LinkedHashMap 的 removeEldestEntry 方法,控制 removeEldestEntry 的移除
//下面的size()方法也是来自于LinkedHashMap,其返回LinkedHashMap当前元素个数
return size()>capacity;
}
}
2 新建一个测试类
public class Test {
public static void main(String[] args) {
LRUCache<String,String> map = new LRUCache<String,String>(5);
map.put("a", "1");
map.put("b", "2");
map.put("c", "3");
map.put("d", "4");
map.put("e", "5");
//输出map的默认顺序
for(Map.Entry<String, String> mEntry : map.entrySet()){
System.out.println(mEntry.getKey()+","+mEntry.getValue());
}
map.get("b");
map.get("d");
map.put("f", "6");
map.put("g", "7");
System.out.println();
//输出map因为访问 导致的顺序改变后的顺序
for(Map.Entry<String, String> mEntry : map.entrySet()){
System.out.println(mEntry.getKey()+","+mEntry.getValue());
}
}
}
运行结果:
a,1
b,2
c,3
d,4
e,5
e,5
b,2
d,4
f,6
g,7
从结果中可以看到 访问map的元素 b ,d 后 d ,b 移动到了链表的最底层,然后map put了两个元素,这两个元素就占据了链表的最底层,并且由于我们创建的缓存容量为5 新增两个元素后,超出了缓存容量,因此将链表最顶端的两个元素 a 和 c删除了。