package com.huawei.test.jdk8.collectiondemo;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author 无极之岚
* @date 2022/2/26 1:02 PM
*/
public class LinkedHashMapTest {
public static void main(String[] args) {
LinkedHashMap<Integer,String> lhm1 = new LinkedHashMap<Integer,String>();
lhm1.put(1,"1");
lhm1.put(2,"2");
lhm1.put(3,"3");
System.out.println("普通方法:");
for (Map.Entry entry:lhm1.entrySet()){
System.out.println(entry.getValue());
}
LinkedHashMap<Integer,String> lhm2 = new LinkedHashMap<Integer,String>(16,0.75f,true);
lhm2.put(1,"1");
lhm2.put(2,"2");
lhm2.put(3,"3");
System.out.println("access为true方法:");
lhm2.get(2);
for (Map.Entry entry:lhm2.entrySet()){
System.out.println(entry.getValue());
}
}
}
世界之大无奇不有,LinkedHashMap 的构造函数放入不同的值,get方法会改变顺序,并且在打印时可以不按照插入顺序。
源码
/**
* Constructs an empty <tt>LinkedHashMap</tt> instance with the
* specified initial capacity, load factor and ordering mode.
*
* @param initialCapacity the initial capacity 初始化容量
* @param loadFactor the load factor 负载因子
* @param accessOrder the ordering mode - <tt>true</tt> for
* access-order, <tt>false</tt> for insertion-order
ture就是访问顺序,false是插入顺序
* @throws IllegalArgumentException if the initial capacity is negative
* or the load factor is nonpositive
*/
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
// 空构造函数默认为false
public LinkedHashMap() {
super();
accessOrder = false;
}
accessOrder影响get函数的实现
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
// accessOrder为true时将获取到的节点移动到尾部
if (accessOrder)
afterNodeAccess(e);
return e.value;
}
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
LRU
Least Recently Used,最少使用,像redis等缓存中间件都有类似的算法,用来过期数据。而LinkedHashMap刚好有个方法removeEldestEntry,当方法返回true时,会将最不常用的节点移除。
/*
* 源码注解中提供了案例,设置最大的长度,超过则返回true,当执行put方法时都会去判断removeEldestEntry是否为true,就执行removeNode方法
<pre>
* private static final int MAX_ENTRIES = 100;
*
* protected boolean removeEldestEntry(Map.Entry eldest) {
* return size() > MAX_ENTRIES;
* }
* </pre>
/
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
实现如下:又上方案例可知,按访问顺序来排,每次get请求都会将数据放队尾,那么只要超过容量时,把队头的节点移除即可。
// 设置容量为10
private static LRUCache<String, Integer> cache = new LRUCache<>(10);
public static void main(String[] args) {
//存入10个数据,之后cache满了
for (int i = 0; i < 10; i++) {
cache.put("Test" + i, i); // 键值对
}
System.out.println("目前所有缓存:" + cache);
cache.get("Test3");
System.out.println("拿了Test3后的缓存:" + cache);
cache.get("Test4");
System.out.println("拿了Test4后的缓存:" + cache);
cache.get("Test5");
System.out.println("拿了Test5后的缓存:" + cache);
cache.get("Test5");
System.out.println("再拿了Test5后的缓存:" + cache);
cache.put("Test" + 10, 10); //cache已经满了,则会将最长没用的删除
System.out.println("添加新元素10后的缓存(此时缓存已满):" + cache);
}
private static class LRUCache<K, V> extends LinkedHashMap<K, V> {
private int cacheSize;
//使用指定的初始容量、装载因子和排序模式构造一个空的LinkedHashMap实例
//true表示访问顺序,false表示插入顺序
public LRUCache(int cacheSize) {
super(16, (float) 0.75, true);
this.cacheSize = cacheSize;
}
//如果不重写这个 会导致在新put数据时,不会删除最久没使用的,而是会新增到后边
@Override
protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
//如果添加数据后,size()大于所要求的容量,则返回true,代表进行LRU删除
return size() > cacheSize; //size()返回此映射中的键值映射数
}
}