LinkedHashMap剖析

来源:互联网 发布:最新淘宝直播怎么申请 编辑:程序博客网 时间:2024/05/16 09:41

一、结构
LinkedHashMap的结构和HashMap一样都由数组和链表构成
区别:
1.LinkedHashMap多了两个指针head,tail,分别指向第一个插入Map中的节点和最后一个插入Map中的节点

/** * The head (eldest) of the doubly linked list. */transient LinkedHashMap.Entry<K,V> head;/** * The tail (youngest) of the doubly linked list. */transient LinkedHashMap.Entry<K,V> tail;

2.相比HashMap,每个LinkedHashMap的节点对象多了两个指针
按插入顺序分别指向前一个节点和后一个节点
源码如下:

static class Entry<K,V> extends HashMap.Node<K,V> {    //多了这两个指针    Entry<K,V> before, after;    Entry(int hash, K key, V value, Node<K,V> next) {        super(hash, key, value, next);    }}

可以看到继承了HashMap的节点对象,但多了before和after两个指针。

所以:LinkedHashMap在HashMap的基础上通过双向练表保持了Map的插入顺序

二、插入操作
LinkedHashMap没有重写HashMap的put函数
但是它重写了创建节点的函数

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {    LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash, key, value, e);    //这个调用是关键    linkNodeLast(p);    return p;}

linkNodeLast(p)源码:

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {    //将Map的last指针指向新插入元素    LinkedHashMap.Entry<K,V> last = tail;    tail = p;    if (last == null)        head = p;    else {        //将原来末尾元素的after指向改插入元素,新插入元素的before指针指向原last元素        p.before = last;        last.after = p;    }}

三、排列顺序
我们知道LinkedHashMap加入的双向链表的概念实现了根据插入顺序排序,其实LinkedHashMap还可以根据LRU 最近最少被使用的调度算法进行排序
1.accessOrder
源码中有这么一个变量accessOrder默认为false
如果为false的话,当对LinkedHashMap进行iterator获取数据的时候,是根据插入顺序排序的,如下例:

public static void main(String[] args) {    Map<String, String> map = new LinkedHashMap<String, String>(16,0.75f,true);    map.put("1", "a");    map.put("2", "b");    map.put("3", "c");    map.put("4", "e");    for (Iterator<String> iterator = map.values().iterator(); iterator.hasNext();) {        String name = (String) iterator.next();        System.out.print(name);    }}

打印结果为:abce,按照加入的顺序打印

那如果通过初始化将accessOrder设置为true呢?如下例

public static void main(String[] args) {    Map<String, String> map = new LinkedHashMap<String, String>(16,0.75f,true);    map.put("1", "a");    map.put("2", "b");    map.put("3", "c");    map.put("4", "e");    //new add    map.get("1");    map.get("2");    for (Iterator<String> iterator = map.values().iterator(); iterator.hasNext();) {        String name = (String) iterator.next();        System.out.print(name);    }}

打印结果为:ceab

这就是基于访问的顺序,get一个元素后,这个元素被加到最后(使用了LRU 最近最少被使用的调度算法)

2.源码实现
LinkedHashMap通过get(key)取元素的时候,会判断一下accessOrder变量是否为ture

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;}

如果为true久需要执行afterNodeAccess(e)函数
将该节点移动到练表末尾

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;    }}
0 0
原创粉丝点击