LinkedHashMap继承于HashMap,同样实现了Map接口,与HashMap不同的是,LinkedHashMap的插入取出是有序的,并且可以控制。先看一下数据结构
其中数字是表示结点插入的顺序,可以看到的是LinkedHashMap用链表将每个元素串起来,数据结构为 数组+单链表+红黑树+双链表。
先看LinkedHashMap的几个属性,因为继承了HashMap,所以HashMap中的非private属性的字段都可以直接进行访问
transient LinkedHashMap.Entryhead;//链表头结点
transient LinkedHashMap.Entryhead;//链表尾结点
final boolean accessOrder; //访问顺序
构造函数:
public LinkedHashMap(int initialCapacity, float loadFactor) { super(initialCapacity, loadFactor); accessOrder = false; }
public LinkedHashMap(int initialCapacity) { super(initialCapacity); accessOrder = false; }
public LinkedHashMap() { super(); accessOrder = false; }
public LinkedHashMap(Map extends K, ? extends V> m) { super(); accessOrder = false;
//调用的是父类的方法 putMapEntries(m, false); }
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) { super(initialCapacity, loadFactor); this.accessOrder = accessOrder; }
accessOrder参数为true表示可以控制访问顺序,默认都是false的,只有在参数中传入才可为true。
其他函数:
newNode()
//当哈希桶中的结点类型是HashMap.code时,调用这个方法
NodenewNode(int hash, K key, V value, Node e) {
//根据传入参数生成对应的Entry结点 LinkedHashMap.Entryp = new LinkedHashMap.Entry (hash, key, value, e);
//把这个结点插入双向链表的结尾 linkNodeLast(p); return p; }
这个方法会在调用put()方法时被调用。每次都将新结点插入到链表末尾,维护了插入的顺序。其中这个Entry
static class Entryextends HashMap.Node {
//首尾指针 Entrybefore, after; Entry(int hash, K key, V value, Node next) { super(hash, key, value, next); } }
newTreeNode()
//当哈希桶中结点为HashMap.TreeNode时调用这个方法
TreeNodenewTreeNode(int hash, K key, V value, Node next) {
//根据传入参数生成新的treeNode结点 TreeNodep = new TreeNode (hash, key, value, next);
//把这个结点插入到双向链表的末尾 linkNodeLast(p); return p; }
afterNodeAccess()
void afterNodeAccess(Nodee) { // move node to last LinkedHashMap.Entry last;
//如果accessOrde参数为true并且访问的结点是不hi尾结点 if (accessOrder && (last = tail) != e) {
//记录p的前后结点 LinkedHashMap.Entryp = (LinkedHashMap.Entry )e, b = p.before, a = p.after;
//p的后结点制空 p.after = null;
//如果p的前结点为空,a为头结点 if (b == null) head = a;
//p的前结点不为空,b的后结点为a else b.after = a;
//p的后结点不为空,a的前结点为b if (a != null) a.before = b;
//p的后结点为空,后结点为最后一个结点 else last = b;
//如果最后一个结点为空,头结点为p if (last == null) head = p;
//如果最后一个结点不为空 p链入最后一个结点后面 else { p.before = last; last.after = p; }
//尾结点为p
tail = p;
++modCount;
}
}
这里有点乱 慢慢理一理就清楚了哈,这个函数会在很多函数中被调用,LinkedHashMap重写了HashMap中的此函数。如果访问顺序为true并且访问的对象不是尾结点,假设访问的结点为2,如图
将结点2放到了链表的尾部
这篇主要解释了LinkedHashMap为什么是有序的以及按照指定顺序的存储方法。在HashMap的基础上看LinkedHashMap压力还是很小的。我会继续努力的,也欢迎指正问题~~