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()返回此映射中的鍵值映射數
}
}