LinkedHashMap 使用場(chǎng)景: 我們需要構(gòu)建一個(gè)空間占用敏感的資源池庐扫,并且希望可以自動(dòng)的釋放掉不常訪問(wèn)的對(duì)象饭望。
構(gòu)造函數(shù)
/**
* Constructs an empty {@code LinkedHashMap} 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 - {@code true} for
* access-order, {@code false} for insertion-order
* @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;
}
initialCapacity 默認(rèn)值是16, loadFactor 默認(rèn)值是0.75f, accessOrder默認(rèn)值是false(也就是默認(rèn)的ordering mode是insertion-order)形庭,如果把a(bǔ)ccessOrder 設(shè)置為true杰妓,這時(shí)候ordering mode 就是 access-order.
那么indertion-order 和access-order 有什么不同呢?
LinkedHashMap 提供了一個(gè) removeEldestEntry 的方法:
/**
* Returns {@code true} if this map should remove its eldest entry.
* This method is invoked by {@code put} and {@code putAll} after
* inserting a new entry into the map. It provides the implementor
* with the opportunity to remove the eldest entry each time a new one
* is added. This is useful if the map represents a cache: it allows
* the map to reduce memory consumption by deleting stale entries.
*
* <p>Sample use: this override will allow the map to grow up to 100
* entries and then delete the eldest entry each time a new entry is
* added, maintaining a steady state of 100 entries.
* <pre>
* private static final int MAX_ENTRIES = 100;
*
* protected boolean removeEldestEntry(Map.Entry eldest) {
* return size() > MAX_ENTRIES;
* }
* </pre>
*
* <p>This method typically does not modify the map in any way,
* instead allowing the map to modify itself as directed by its
* return value. It <i>is</i> permitted for this method to modify
* the map directly, but if it does so, it <i>must</i> return
* {@code false} (indicating that the map should not attempt any
* further modification). The effects of returning {@code true}
* after modifying the map from within this method are unspecified.
*
* <p>This implementation merely returns {@code false} (so that this
* map acts like a normal map - the eldest element is never removed).
*
* @param eldest The least recently inserted entry in the map, or if
* this is an access-ordered map, the least recently accessed
* entry. This is the entry that will be removed it this
* method returns {@code true}. If the map was empty prior
* to the {@code put} or {@code putAll} invocation resulting
* in this invocation, this will be the entry that was just
* inserted; in other words, if the map contains a single
* entry, the eldest entry is also the newest.
* @return {@code true} if the eldest entry should be removed
* from the map; {@code false} if it should be retained.
*/
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
這個(gè)方法默認(rèn)返回false也就是說(shuō)LinkedHashMap在新增鍵值對(duì)時(shí)LinkedHashMap并不會(huì)刪除已有的“老的”元素碘勉,我們可以重寫(xiě)這個(gè)方法用來(lái)刪除map里面最“老”的元素巷挥。
比如,如果我們希望在增加第4個(gè)元素時(shí)希望刪掉它里面最“老”的元素验靡。
在創(chuàng)建鏈表的時(shí)候重寫(xiě)該方法倍宾, return size() >3 的意思是:當(dāng)LinkedHashMap里面的元素個(gè)數(shù)大于3時(shí),就啟動(dòng)LinkedHashMap 刪除最“老”元素的功能:
LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>(16, 0.75f, true){
@Override
protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
return size() > 3;
}
};
我們給LinkedHashMap添加3個(gè)元素胜嗓,然后通過(guò)foreach來(lái)打印它里面的所有元素高职。
linkedHashMap.put("project1", "1");
linkedHashMap.put("project2", "2");
linkedHashMap.put("project3", "3");
linkedHashMap.forEach((k, v) -> {
System.out.println("key: " + k + ", value: " + v);
});
輸出結(jié)果:
key: project1, value: 1
key: project2, value: 2
key: project3, value: 3
這時(shí)候我們添加第4個(gè)元素,
linkedHashMap.put("project1", "1");
linkedHashMap.put("project2", "2");
linkedHashMap.put("project3", "3");
linkedHashMap.forEach((k, v) -> {
System.out.println("key: " + k + ", value: " + v);
});
linkedHashMap.put("project4", "4");
System.out.println("After changed;");
linkedHashMap.forEach((k, v) ->{
System.out.println("key: " + k + ", value: " + v);
});
輸出結(jié)果:
key: project1, value: 1
key: project2, value: 2
key: project3, value: 3
After changed;
key: project2, value: 2
key: project3, value: 3
key: project4, value: 4
可以看到LinkedHashMap 把鍵值對(duì)("project1":"1")的元素刪除了辞州,新增了("project4":"4")的元素怔锌,元素的總數(shù)還是保持3個(gè)。
我們已經(jīng)設(shè)置了LinkedHashMap的ordering mode 為access-order, 但是我們并沒(méi)有訪問(wèn)LinkedHashMap任何其中的一個(gè)元素,所以在刪除元素時(shí)埃元,LinkHashMap刪除了第一個(gè)被添加進(jìn)去的元素涝涤。
我們?cè)囍L問(wèn)下LinkedHashMap里面的元素,看看被刪除的元素會(huì)是哪一個(gè)岛杀。
linkedHashMap.put("project1", "1");
linkedHashMap.put("project2", "2");
linkedHashMap.put("project3", "3");
linkedHashMap.forEach((k, v) -> {
System.out.println("key: " + k + ", value: " + v);
});
//訪問(wèn)了第一個(gè)元素
linkedHashMap.get("project1");
linkedHashMap.put("project4", "4");
System.out.println("After changed;");
linkedHashMap.forEach((k, v) ->{
System.out.println("key: " + k + ", value: " + v);
});
輸出結(jié)果:
key: project1, value: 1
key: project2, value: 2
key: project3, value: 3
After changed;
key: project3, value: 3
key: project1, value: 1
key: project4, value: 4
可以看到第二個(gè)被添加進(jìn)LinkedHashMap的元素被刪除了阔拳。(第二個(gè)元素和第三個(gè)元素都沒(méi)有被訪問(wèn),但是第二個(gè)元素是先于第三個(gè)元素被添加到LinkedHashMap中的)类嗤。
我們可以得到如下結(jié)論:
如果沒(méi)有重寫(xiě)LinkedHashMap removeEldestEntry方法糊肠,那么新添加元素時(shí),它不會(huì)刪除已經(jīng)存在的元素遗锣。
如果重寫(xiě)了LinkedHashMap removeEldestEntry方法货裹,accessOrder為false,當(dāng)新添加元素時(shí)精偿,它會(huì)刪除Map里正存在的并且最早被添加進(jìn)來(lái)的元素泪酱。
如果重寫(xiě)了LinkedHashMap removeEldestEntry方法, 并且accessOrder為true,當(dāng)新添加元素時(shí)还最,(1)如果map里面有未被訪問(wèn)過(guò)的元素墓阀,它會(huì)刪除未被訪問(wèn)過(guò)的所有元素里最早被添加進(jìn)去的元素。(2)如果map里所有的元素都被訪問(wèn)過(guò)拓轻,它會(huì)刪除最早被訪問(wèn)過(guò)的元素斯撮。
注意:
當(dāng) ordering mode是 insertion-order 時(shí),更新(reinsert)一個(gè)已經(jīng)存在的鍵值并不會(huì)改變insertion order.
當(dāng)ordering mode是 access-order時(shí)扶叉,put, putIfAbsent,
get, getOrDefault, compute, computeIfAbsent,
computeIfPresent, merge 等方法都會(huì)改變 access order 的順序勿锅。