LinkedHashMap

单看该类名称。Linked链表+HashMap,不看类实现也能从字面猜出其大概功能。是把HashMap做了有序处理。即对传统的HashMap做了二次加工。这样,在对HashMap使用过程中又有对顺序有要求的情况下,可以直接使用LinkedHashMap,避免了开发者维护顺序的操作。该类的重点就是加入双向链表保证了顺序

public class LinkedHashMap<K,V> extends HashMap<K,V>  implements Map<K,V>

继承HashMap,实现Map接口

LinkedHashMap中存在的实例属性

//The head of the doubly linked list.
private transient LinkedHashMapEntry<K,V> header;

看注释:doubly linked list 双向链表 head表示双向链表的头
看声明:LinkedHashMapEntry类型,经验告诉我们这是一个内部类,是双向链表的Entry体,找LinkedHashMapEntry体的实现

private static class LinkedHashMapEntry<K,V> extends HashMapEntry<K,V>

真是LinkedHashMap的静态内部类,继承自HashMapEntry
构造方法直接调用的super

LinkedHashMapEntry(int hash, K key, V value, HashMapEntry<K,V> next) {
     super(hash, key, value, next);
}
// These fields comprise the doubly linked list used for iteration.
LinkedHashMapEntry<K,V> before, after;

Entry里的before,after是用来构成双向链表的基础,提供iteration遍历用,确保了put元素后的有序性,Entry里提供了remove(),addBefore()与recordAccess()方法,remove与addBefore操作都比较简单,remove从doublyLinkedList中remove掉该Entry;addBefore将该Entry对象插入到参数entry前面,不过多分析,下面看下recordAccess()方法

/**
 * This method is invoked by the superclass whenever the value
 * of a pre-existing entry is read by Map.get or modified by Map.set.
 * If the enclosing Map is access-ordered, it moves the entry
 * to the end of the list; otherwise, it does nothing.
 */
void recordAccess(HashMap<K,V> m) {
      LinkedHashMap<K,V> lm = (LinkedHashMap<K,V>)m;
      if (lm.accessOrder) {
            lm.modCount++;
            remove();
            addBefore(lm.header);
       }
}

看方法注释有点慒,如果accessOrder为空,就一空方法。那来看下accessOrder属性与赋值的地方

/**
 * The iteration ordering method for this linked hash map: <tt>true</tt>
 * for access-order, <tt>false</tt> for insertion-order.
 *
 * @serial
 */
private final boolean accessOrder;

true:访问顺序;false:插入顺序
定义成final了,通篇没有看到accessOrder为true的构造(只在构造里对其赋值了)
但有一个传进来的赋值

public LinkedHashMap(int initialCapacity,float loadFactor,boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

查看这个构造的创建,在LruCache与DiskBasedCache类里有调用,且传值都为true。
那继续分析recordAccess方法,在accessOrder为true时,方法才有意义,即访问顺序时才有意义,正好匹配了LruCache的初衷:Least recently used,最近最少使用,查看LinkedHashMap的get方法

public V get(Object key) {
        LinkedHashMapEntry<K,V> e = (LinkedHashMapEntry<K,V>)getEntry(key);
        if (e == null)
            return null;
        e.recordAccess(this);
        return e.value;
}

getEntry是父类HashMap方法,不介绍,获取entry对象后,如果有参数key对应的entry对象后,先执行了recordAccess方法。我们分析recordAccess方法,在访问顺序时,将该entry从链表中移除,并将entry插入到doublylinkedlist的header前。即通过LruCache的get方法保证常用的元素保持在链表头部。(如果为插入顺序的话,则recordAccess方法空跑)

这样LinkedHashMap,通过对LinkedHashMapEntry,增加了before与after属性,实现了双向链表的数据结构,复写了init方法(在父类HashMap中的构造里调用),将双向链表创建

@Override
void init() {
        header = new LinkedHashMapEntry<>(-1, null, null, null);
        header.before = header.after = header;
}

在LinkedHashMap再调用put方法时,保证了存储的有序性

解释一下HashMap为啥无序。因为HashMap是用数组+链表的数据结构存储数据。为了解决hash冲突(解决到底存入数组的哪个链表中),做了h & (length-1);操作就是取模的优化写法。导致了put进数据的无序,数据元素中的单链表还是可以保持链表内的局部有序。但在大结构中无法保证有序。

LinkedHashMapEntry加入了before与after(独立于next属性),将数组元素内各链表重新做双向关联,确保了其有序性。在LinkedHashMap中加了accessOrder属性,在LrcCache类使用LinkedHashMap,传入accessOrder为true的参数,可以保证了最后访问的在链表的最前面。

PS:看的太粗陋,有时间的话还要再看两遍,三遍。并没有系统的看,愁进了方法,有错误,不妥的地方,还请各位看客即时指出。谢谢。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,045评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,114评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,120评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,902评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,828评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,132评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,590评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,258评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,408评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,335评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,385评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,068评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,660评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,747评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,967评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,406评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,970评论 2 341

推荐阅读更多精彩内容