LinkedHashMap是HashMap的一个子类。上一节初步分析了HashMap,本节分析了LinkedHashMap。LinkedHashMap的数据结构EntryLinkedHashMap的Entry继承自HashMap的Node。除了Node数据结构外,还增加了before和after,所以我们可以猜测LinkedHashMap的Entry应该是双向链表结构:staticclassEntryextendsHashMap.Node{Entry之前,之后;Entry(inthash,Kkey,Vvalue,Nodenext){super(hash,key,value,next);另外,LinkedHashMap定义了头节点和尾节点:transientLinkedHashMap.Entryhead;/***双向链表的尾部(最年轻的)。*/transientLinkedHashMap.Entrytail;table数组继承自HashMap,没有变化!数据仍然存储在表数组中,不同的是表中的对象变成了Entry。LinkedHashMap的初始化和HashMap的初始化方法基本相同,还有涉及到的容量、加载因子、扩展阈值等概念。但是,增加了一个概念accessOrder。javadoc的解释是定义遍历访问顺序。当值为true时,按照访问顺序排序,当值为false时,按照插入顺序排序。/***此链接哈希映射的迭代排序方法:true*用于访问顺序,false用于插入顺序。**@serial*/finalbooleanaccessOrder;LinkedHashMapAssignmentLinkedHashMap赋值逻辑如下(假设要存储的数据为e):检查表数组是否为空,初始化表数组指定容量或者defaultcapacity并根据key1的hash值进行计算(算法是(capacity-1)&hash(key1)对应的bucket)。这一步非常重要。一般来说,一个优秀的哈希算法可以保证不同的键值尽可能得到不同的哈希值,也可以保证它们被放在不同的桶中。但难免会出现不同key值得到相同hash值的情况(hash冲突:key1<>key2,hash(key1)=hash(key2)),这种情况下会被放到同一个bucket中(如表[5])。拿到bucket之后判断bucket中是否有数据。如果没有数据,直接新建一个Node:newNode(hash,key1,value1,null),放入桶中,结束LinkedHashMap。新创建的Node是它的Entry对象,所以创建对象的过程和HashMap略有不同:创建是双向链表(通过before和after首尾相连),在创建时指定LinkedHashMap的head和tail创作过程。否则,如果桶中有数据,则有两种情况:一种是key值key1重复赋值,另一种是hash冲突。如果是hash冲突,则新建一个Node:newNode(hash,key1,value1,null)并设置为bucket中的最后一个Node。如果是重复赋值(bucket中数据的key值=key1),则对key1重新赋值value1,返回key1的旧值。HashMap的赋值过程与HashMap的赋值过程基本相同,只是数据是分配在哈希桶中,同时根据数据的存放顺序创建一个双向链表。从LinkedHashMap获取数据通过key值从LinkedHashMap获取数据的逻辑和HashMap完全一样通过get(key)方法获取数据的逻辑如下(假设获取的数据为key=key1):表数组不为空且数组长度大于0,然后使用与put数据相同的算法得到key1值对应的bucket。如果桶不为空,则从第一个节点开始检查。如果节点的键值等于key1,则返回节点的值。如果第一个节点不满足条件,则依次检查桶中的所有其他节点。如果桶为空,或者桶不为空但没有找到满足条件的对象(应该不可能),则返回null,表示当前HashMap中不存在键值为key1的对象。所以我们可以看到,正如名字给我们的启发,LinkedHashMap和HashMap的区别就是多了一个链表。大家都知道LinkedHashMap可以保证数据是按照入库的顺序获取的,而HashMap遍历的数据是随机的。下一次我们将详细分析背后的原因。