Java之LinkedHashMap源码分析(第一篇:初步了解)

(注意:本文基于JDK1.8)

前言

    HashMap是我们经常使用的容器对象,遍历HashMap持有的元素时,没有任何顺序而言,HashMap遍历元素的顺序,与你插入元素、访问元素都没有任何关系!很多时候,我们需要一个特定的顺序去遍历HashMap存储的元素,比如需要按照元素插入的顺序遍历或者按照元素被访问的顺序遍历元素,但是HashMap不行,HashMap只能依照Key对象的hashCode()方法生成桶地址顺序遍历(这个不可控)!那么如何做到按照某个特定顺序遍历Map中的元素呢?

答案:LinkedHashMap支持按照插入元素的顺序去遍历所有元素,也支持按照元素的访问顺序去遍历所有元素!

LinkedHashMap支持2种有序的方式遍历元素,它们是

1:按照元素插入的先后顺序遍历元素(默认),此时遍历元素的顺序与你插入元素时的顺序一致

2:按照元素访问的先后顺序遍历元素,此时遍历元素的顺序与你访问每个元素的顺序一致(如果没有访问过元素呢?相信学习完这一系列文章,你应该能找到答案)

 

LinkedHashMap保持遍历元素有序的技术点

1、LinkedHashMap对象持有一个双向链表,这就是LinkedHashMap可以遍历所有元素时保持有序的原因!

    transient LinkedHashMap.Entry<K, V> head;
    transient LinkedHashMap.Entry<K, V> tail;

LinekdHashMap对象持有的实例变量head表示双向链表的第一个结点,持有的另一个实例变量tail表示双向链表的最后一个结点

 

2、Entry结点类

Entry类定义在LinkedHashMap的内部,它产生的每个对象表示双向链表的一个结点

    static class Entry<K, V> extends Node<K, V> {
        LinkedHashMap.Entry<K, V> before;
        LinkedHashMap.Entry<K, V> after;

        Entry(int var1, K var2, V var3, Node<K, V> var4) {
            super(var1, var2, var3, var4);
        }
    }

Entry类作为静态内部类定义在LinkedHashMap中,Entry继承了HashMap中定义的静态内部类Node,在Node类的基础上新增一个表示前驱结点的实例变量before,新增一个表示后继结点的实例变量after,这样的结点对象就可以作为双向链表的结点了

 

3、LinkedHashMap对象支持两种遍历元素顺序的方式,遍历元素的顺序取决于当前LinkedHashMap对象持有的一个标志位accessOrder

final boolean accessOrder;

false:代表按照插入元素的顺序去组织双向链表(默认)

true:代表按照访问元素的顺序去组织双向链表

 

4、LinkedHashMap对象持有的accessOrder在哪赋值?

accessOrder由final修饰,所以它是在创建LinkedHashMap对象的时候必须显式赋值,它是在构造方法中赋值的,中途无法更改(忽略反射方式)

LinkedHashMap提供5个构造方法用于创建对象,截图红圈处的那个构造方法可以指定accessOrder的值,其他构造方法accessOrder的初始值均是false!

true:表示按照元素访问顺序

false:表示按照元素插入顺序

 

LinkedHashMap类结构

public class LinkedHashMap<K,V>
    extends HashMap<K,V>
    implements Map<K,V>
{
    ………………省略很多代码………………
}

    LinkedHashMap继承HashMap并实现了Map接口,如果你熟悉HashMap,一定记得在父类的HashMap中定义了3个空的方法,这3个空的方法正是给LinkedHashMap使用的……LinkedHashMap与HashMap的多数功能是一样的,LinkedHashMap只是比HashMap支持按照元素的插入顺序或者访问顺序遍历元素的功能,所以LinkedHashMap继承HashMap再合适不过!

 

LinekdHashMap重写父类的3个方法(模版方法设计模式牛X应用)

    LinkedHashMap重写了HashMap中的定义的3个空的方法,这三个方法是:

1、afterNodeAccess方法

2、afterNodeInsertion方法

3、afterNodeRemoval方法

    void afterNodeAccess(HashMap.Node<K, V> var1) {
    }

    void afterNodeInsertion(boolean var1) {
    }

    void afterNodeRemoval(HashMap.Node<K, V> var1) {
    }

   

LinekdHashMap重写了newNode()方法

    LinkedHashMap也重写了另一个重要的创建结点对象的newNode方法,该newNode方法负责创建Entry对象

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

 

总结

    LinkedHashMap也是一个只能在单线程下使用的容器对象,我们接下来一起详细学习LinkedHashMap对象的创建、插入元素、删除元素、遍历元素、以及LinkedHashMap是如何巧妙在HashMap基础上做到保持有序的…………请看下一篇…………

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值