Java集合源码实现四:LinkedHashMap(jdk1.8)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_23830637/article/details/79020118

Java集合源码实现四:LinkedHashMap(jdk1.8)

类继承关系:

这里写图片描述

什么是LinkedHashMap

       哈希表和Map接口的链表实现,与HashMap的不同之处 在于它维护着一个双向链表,这个链表定义了迭代排序,通常是插入顺序。
* 如果将键重新插入中,则插入顺序不受影响。

LinkedHashMap数据结构

这里写图片描述
       LinkedHashMap是基于HashMap实现的,只是在HashMap的基础上增加了双向链表而已。
(这里直接把上一篇的HashMap里的数据结构图简单改了下)

源码分析:

1.类继承实现

public class LinkedHashMap<K,V>
    extends HashMap<K,V> implements Map<K,V>
{
    //方法....
}

LinkedHashMap继承HashMap所具有的特性基本一致,这里不重复了。(点击跳转Java集合源码实现三:HashMap(jdk1.8))。

2.成员变量

/**
 * 首节点
 */
transient LinkedHashMap.Entry<K,V> head;

/**
 * 尾节点
 */
transient LinkedHashMap.Entry<K,V> tail;

/**
 * 排序规则方式
 * true 按访问顺序排序 
 * false 默认按插入顺序排序
 */
final boolean accessOrder;

在hashMap的基础上又扩展了3个属性,用于双向链表。

3.LinkedHashMap中的链表节点

/**
 * 继承HashMap.Node 
 */
static class Entry<K,V> extends HashMap.Node<K,V> {
    //before当前元素的上一个节点
    //after当前元素的下一个节点
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

4.主要方法

构造方法

1.

/**
 * 调用HashMap的构造方法
 */
public LinkedHashMap() {
    super();
    //默认按插入顺序排序
    accessOrder = false;
}

2.

/**
 * 调用HashMap的构造方法
 */
public LinkedHashMap(int initialCapacity) {
    super(initialCapacity);
    //默认按插入顺序排序
    accessOrder = false;
}

3.

/**
 * 调用HashMap的构造方法
 */
public LinkedHashMap(int initialCapacity, float loadFactor) {
    super(initialCapacity, loadFactor);
    //默认按插入顺序排序
    accessOrder = false;
}

4.

/**
 * 调用HashMap的构造方法
 */
public LinkedHashMap(Map<? extends K, ? extends V> m) {
    super();
    //默认按插入顺序排序
    accessOrder = false;
    putMapEntries(m, false);
}

5.

/**
 * 调用HashMap的指定参数的构造方法
 * 并且指定排序方式
 */
public LinkedHashMap(int initialCapacity,
                     float loadFactor,
                     boolean accessOrder) {
    super(initialCapacity, loadFactor);
    this.accessOrder = accessOrder;
}

添加,删除方法

LinkedHashMap中并没有重写父类HashMap的put,remove等方法。均是调用其父类的方法实现。

afterNodeAccess方法(移动节点到最后的方法)

LinkedHashMap通过重写afterNodeAccess方法,使put()方法将节点插入到尾部。这也就是HashMap中afterNodeAccess()为空方法的原因,它是为LinkedHashMap服务的。

void afterNodeAccess(Node<K,V> e) { // move node to last
    LinkedHashMap.Entry<K,V> last;
    //当accessOrder为true 并且e不是最后一个节点的时
    if (accessOrder && (last = tail) != e) {
        //a为p的下一个节点
        //b为p的上一个节点
        LinkedHashMap.Entry<K,V> p =
            (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
        //p的下一个节点置null
        p.after = null;
        //b==null,即当前节点为首节点,更新首节点为a
        if (b == null)
            head = a;
        else//当前节点不是首节点,修改b的下一个节点为a
            b.after = a;
        if (a != null) //a!=null,即当前结点不是尾节点
            a.before = b;//更新a的上一个节点为b
        else
            last = b;//最后一个节点更新为b
        if (last == null)//如果最后一个节点为null
            head = p;//首节点更新为p
        else {
            p.before = last;//p的上一个节点更新为最后一个节点
            last.after = p;//最后一个节点的下一个节点更新为p
        }
        //尾节点修改为p
        tail = p;
        //操作次数增加
        ++modCount;
    }
}

afterNodeRemoval方法

在移除节点时通过调用afterNodeRemoval()来更新首尾节点,与afterNodeAccess()同理。

void afterNodeRemoval(Node<K,V> e) { // unlink
    //a为p的下一个节点
    //b为p的上一个节点
    LinkedHashMap.Entry<K,V> p =
        (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
    p.before = p.after = null;

    if (b == null) //b为null,即当前节点为首节点
        head = a;//更新首节点为a
    else//即当前节点不是首节点
        b.after = a;//更新b的下一个节点为a
    if (a == null)//a为null,当前节点为尾节点
        tail = b;//更新尾节点为b
    else//即当前节点不是尾节点
        a.before = b;//更新a的上一个节点为b
}

获取元素

/**
 * 获取元素
 */
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;
}

LinkedHashMap获取元素与HashMap基本相同,getNode()与hash()方法都是调用HashMap的方法,唯一区别是具有排序方式,如果accessOrder为false,则不需要修改获取的元素的顺序,按默认的插入顺序排序,如果为true,需要调用afterNodeAccess()把获取的节点移动到最后。


猜你喜欢

转载自blog.csdn.net/qq_23830637/article/details/79020118