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方法

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
}


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

获取元素

/**
 * 获取元素
 */
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()把获取的节点移动到最后。
--------------------- 
原文:https://blog.csdn.net/qq_23830637/article/details/79020118 

LinkedHashMap 是继承自 HashMap 的类,在 HashMap 的基础上通过维护一条双向链表来解决无法保持遍历顺序和插入顺序一致的问题,并提供了对访问顺序的支持。在 JDK 1.8 版本中,LinkedHashMap 使用了和 HashMap 相同的底层数据结构,即拉链式散列结构,并在解决长链表问题上引入了红黑树优化。这样,LinkedHashMap 可以提供高效的增删改查操作,并且在遍历时可以按照插入或访问的顺序进行遍历。 LinkedHashMap 的底层数据结构和 HashMap 一样,都是使用数组加链表或红黑树的方式来处理冲突。每个数组元素都是一个链表或红黑树的头节点,每个节点包含一个键值对。当插入或查找元素时,根据键的哈希值找到对应的数组下标,然后在链表或红黑树中进行操作。 在 LinkedHashMap 中,除了继承了 HashMap 的方法,还覆写了部分方法来维护双向链表。具体来说,LinkedHashMap 在 put、remove 和 get 等方法中添加了对双向链表的操作,以保证插入和访问的顺序。当插入一个新的元素时,LinkedHashMap 会将该元素插入到链表的末尾;当访问一个已有元素时,LinkedHashMap 会将该元素移动到链表的末尾。通过这种方式,LinkedHashMap 可以保持元素的插入或访问顺序,实现了有序遍历的效果。 总结起来,LinkedHashMap 的底层原理是在 HashMap 的基础上通过维护一条双向链表来实现插入和访问的顺序,而在 JDK 1.8 中,LinkedHashMap 使用了和 HashMap 相同的底层数据结构,即拉链式散列结构,并引入了红黑树优化。这样,LinkedHashMap 可以提供高效的增删改查操作,并且在遍历时可以按照插入或访问的顺序进行遍历。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [LinkedHashMap(JDK1.8)源码解析](https://blog.csdn.net/qq_41242680/article/details/114637171)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值