【Java基础】LinkedHashMap的实现

本文详细介绍了Java中的LinkedHashMap,它是一个保持插入顺序或访问顺序的哈希表和链表数据结构。相比于HashMap,LinkedHashMap在迭代时与容量无关,性能更优。accessOrder标志决定是按插入顺序还是访问顺序遍历。在put和get操作时,LinkedHashMap会相应地调整节点位置。此外,还讨论了其内部结构,包括头尾节点的维护和迭代器的工作原理。
摘要由CSDN通过智能技术生成

首先,查看LinkedHashMap的注释,了解到它主要有以下几点需要注意,后面将分别贴出对应代码,进行理解

一、LinkedHashMap的几点特性

  1. 持有一个双向链表,与hashMap和hashTable不同,它可以保持插入顺序。相比treeMap,它可以拥有更高的性能(后者留待后面研究treeMap之后再填坑)。
  2. 它很适合创建LRU队列。原因:有一个比较特殊的构造函数(LinkedHashMap(int,float,boolean)) ,可使按照最近访问的顺序进行迭代
  3. collection-views是什么,access-ordered 与insertion-ordered是什么
  4. 它相对hashmap,因为要维护双向链表可能会稍微多点性能开销,但有一个例外:linkedHashmap对collection-view的迭代时间开销与size有关,与capacity无关,hashmap则与capacity也有关(此处如何理解?)
  5. 两个参数会影响性能:初始容量负载因子
  6. 非线程安全
  7. 关于插入顺序,对于insertion-ordered,如果插入的key已经存在,而仅仅只 改变key的值,则不会改变插入顺序。对于access-ordered,使用get查询是一个结构性修改
  8. 任何未通过迭代器进行的结构性调整都会导致ConcurrentModificationException

二、代码理解

接下来,先上它的底层存储结构,比较与hashMap的不同:

// 是hashmap的子类
public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
// 双向链表的头
transient LinkedHashMap.Entry<K,V> head;
// 双向链表的尾
transient LinkedHashMap.Entry<K,V> tail;
// 当为true时,表示迭代器会按访问顺序遍历,false则按插入顺序遍历。默认值是false
final boolean accessOrder;

LinkedHashMap 的主要特性在于根据accessOrder,维持遍历顺序,

// 在hashmap中调用put方法时,会执行此方法,主要做的操作是判断是否要移除第一个节点
 void afterNodeInsertion(boolean evict) { // possibly remove eldest
        LinkedHashMap.Entry<K,V> first;
        // 注意:当linkedhashmap第一次添加元素时,head并不是null,而是“C:\Program Files\Java\jdk1.8.0_271\jre\bin\”下面的节点,为何这样设计?
        // 另外removeEldestEntry涉及到io下的ExpiringCache,根据当前map的size是否超过MAX_ENTRIES(200),决定是否执行removeNode方法
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            // 此处调用的还是父类hashmap的removeNode
            removeNode(hash(key), key, null, false, true);
        }
    }

	// 此方法做的操作是,当处于访问顺序模式,将进行了访问的节点提到链表的末尾
    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, prev = p.before, next= p.after;
 				// 代码省略
 				.....
        }
    }

三、小结

接下来解答以下特点(部分知识点暂时欠缺,留坑)

  1. linkedHashMap如何保持插入顺序?
// 在hashMap中已经预留了此方法,并由linkedHashMap进行覆盖,插入节点时,进行链表操作
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
        LinkedHashMap.Entry<K,V> last = tail;
        tail = p;
        if (last == null)
            head = p;
        else {
            p.before = last;
            last.after = p;
        }
    }

2.linkedHashmap的迭代为何与容量无关?因为linkedHashmap迭代的是链表,只与数据有关。而hashmap是遍历底层数组,所以与容量有关。
3.access-ordered 与insertion-ordered是在创建linkedHashMap的时候确定的,表示链表的访问顺序,一旦确立无法改变

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值