栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JavaSE集合实现原理——LinkedHashMap

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JavaSE集合实现原理——LinkedHashMap

前言

        这是我关于“JavaSE集合实现原理”系列的第二篇博文,这次解析linkedHashMap的实现原理。记得有一次参加面试时,面试官问我:“你说的输入这么多,那你的输出呢?”;我便机智的回答:“写博客、工作当中”。虽然搪塞了过去,但实际上我的博客输出很少(工作中还是有输出的)。什么东西都得自己看了,摸了,分析了,心理才有底有勇气去和别人侃侃而谈(譬如面试)。现在我要立下Flag,坚持写博客,利用好三年黄金期!


参考

        【01】JavaSE集合实现原理——HashMap


类关系图

图(1) linkedHashMap相关类关系图 

这张自动生成的关系图可能不太友好,在这儿语言描述一下:linkedHashMap继承自HashMap,其中扩展了linkedHashMap.Entry类继承自HashMap.Node类。

类解释(关键的类):

  • linkedHashMap继承自HashMap,进行了扩展:使键值映射Entry有序,默认顺序为插入顺序
  • Entry是linkedHashMap的内部类,继承自HashMap.Node,增加了双向链表的功能。这个双向链表作用是保证键值映射(Entry)的增加、遍历是有序的。
  • 其他类可以不关注,关于HashMap的类解释请参考【01】

 

开始  一、概述

        linkedHashMap是HashMap的增强版,继承自HashMap。增强功能为:记录键值顺序,默认顺序为插入顺序。linkedHashMap中源码相比HashMap就很少了,因为它仅仅需要覆关键的方法即可——操作节点方法(newNode、replacementNode、newTreeNode、replacementTreeNode),在这些方法中将节点在链表(head、tail)中进行相应的操作。

二、成员变量 
    
    transient linkedHashMap.Entry head;

    
    transient linkedHashMap.Entry tail;

    
    final boolean accessOrder;

head、tail:见名知意:一个用来保存链条的头部元素,一个用来保存链条的尾部元素。元素节点顺序将使用这条链表来做记录。

accessOrder:从注释上面可以清楚的知道,该值用来控制链表顺序是节点插入顺序、还是访问顺序。另外也是控制是LRU,或是FIFO内存淘汰机制的关键参数。

 

三、节点顺序控制方法
  // ------- 访问控制 ------
   public V get(Object key) {
        Node e;
        if ((e = getNode(hash(key), key)) == null)
            return null;
        if (accessOrder)
            afterNodeAccess(e);
        return e.value;
    }

    public V getOrDefault(Object key, V defaultValue) {
       Node e;
       if ((e = getNode(hash(key), key)) == null)
           return defaultValue;
       if (accessOrder)
           afterNodeAccess(e);
       return e.value;
   }  

  // ------- 插入控制 ------
  Node newNode(int hash, K key, V value, Node e) {
        linkedHashMap.Entry p =
            new linkedHashMap.Entry(hash, key, value, e);
        linkNodeLast(p);
        return p;
    }

    Node replacementNode(Node p, Node next) {
        linkedHashMap.Entry q = (linkedHashMap.Entry)p;
        linkedHashMap.Entry t =
            new linkedHashMap.Entry(q.hash, q.key, q.value, next);
        transferlinks(q, t);
        return t;
    }

    TreeNode newTreeNode(int hash, K key, V value, Node next) {
        TreeNode p = new TreeNode(hash, key, value, next);
        linkNodeLast(p);
        return p;
    }

    TreeNode replacementTreeNode(Node p, Node next) {
        linkedHashMap.Entry q = (linkedHashMap.Entry)p;
        TreeNode t = new TreeNode(q.hash, q.key, q.value, next);
        transferlinks(q, t);
        return t;
    }

1、节点访问方法get()、getOrDefault()会根据accessOrder的设置来确定是否调整节点位置。

2、*TreeNode()、*Node()将新增节点放置链表末尾。


实现LRU、FIFO内存淘汰机制的关键方法

        linkedHashMap提供了实现该算法的关键方法linkedHashMap#removeEldestEntry ,该方法将在插入新节点时调用:

    void afterNodeInsertion(boolean evict) { // possibly remove eldest
        linkedHashMap.Entry first;
        if (evict && (first = head) != null && removeEldestEntry(first)) {
            K key = first.key;
            removeNode(hash(key), key, null, false, true);
        }
    }

这个方法相信大家都有印象,它是HashMap提供的勾子方法。linkedHashMap的逻辑覆盖很简单,被调用方法removeEldestEntry饭回true时将删除链表头部元素。因此需要了解LRU、FIFO的基本含义:

  • LRU:最近最少使用
  • FIFO:先进先出          

 从源代码中得知,删除的永远是head这个变量对应的值,再看看节点访问与插入时都是控制节点放置tail变量中就能理解了。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/310478.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号