JDK源码分析(6)之 LinkedHashMap 相关 (2)

afterNodeAccess可以算是LinkedHashMap比较核心的方法了,当访问了一个节点的时候,如果accessOrder = true则将节点放到最后,如果accessOrder = false则不变;

void afterNodeInsertion(boolean evict) { // possibly remove eldest LinkedHashMap.Entry<K,V> first; if (evict && (first = head) != null && removeEldestEntry(first)) { K key = first.key; removeNode(hash(key), key, null, false, true); } } protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; }

afterNodeInsertion方法是插入节点后是否需要移除最老的节点,这个方法和维护链表无关,但是对于LinkedHashMap的用途有很大作用,后天会举例说明;

2. get 方法 public V get(Object key) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return null; if (accessOrder) afterNodeAccess(e); return e.value; } public V getOrDefault(Object key, V defaultValue) { Node<K,V> e; if ((e = getNode(hash(key), key)) == null) return defaultValue; if (accessOrder) afterNodeAccess(e); return e.value; }

get方法主要也是通过afterNodeAccess来维护链表位置关系;
以上就是LinkedHashMap链表位置关系调整的主要方法了;

3. containsValue 方法 public boolean containsValue(Object value) { for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) { V v = e.value; if (v == value || (value != null && value.equals(v))) return true; } return false; }

可以看到LinkedHashMap还重写了containsValue,在HashMap中寻找value的时候,需要遍历所有节点,他是遍历每个哈希桶,在依次遍历桶中的链表;而在LinkedHashMap里面要遍历所有节点的时候,就可以直接通过双向链表进行遍历了;

三、应用 public class Cache<K, V> { private static final float DEFAULT_LOAD_FACTOR = 0.75f; private final int MAX_CAPACITY; private LinkedHashMap<K, V> map; public Cache(int capacity, boolean accessOrder) { capacity = (int) Math.ceil((MAX_CAPACITY = capacity) / DEFAULT_LOAD_FACTOR) + 1; map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, accessOrder) { @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CAPACITY; } }; } public synchronized void put(K key, V value) { map.put(key, value); } public synchronized V get(K key) { return map.get(key); } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry entry : map.entrySet()) { sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue())); } return sb.toString(); } }

以上是就是一个LinkedHashMap的简单应用,

当accessOrder = true时,就是LRUCache,

当accessOrder = false时,就是FIFOCache;

// LRUCache Cache<String, String> cache = new Cache<>(3, true); cache.put("a", "1"); cache.put("b", "2"); cache.put("c", "3"); cache.put("d", "4"); cache.get("c"); System.out.println(cache);

// 打印:b:2 d:4 c:3

// FIFOCache Cache<String, String> cache = new Cache<>(3, false); cache.put("a", "1"); cache.put("b", "2"); cache.put("c", "3"); cache.put("d", "4"); cache.get("c"); System.out.println(cache);

// 打印:b:2 c:3 d:4

总结

总体而言LinkedHashMap的代码比较简单,但是我觉得里面代码的组织,逻辑的提取等方面特别值得借鉴;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpgszp.html