Java集合类:LinkedHashMap原理分析

127 阅读1分钟

我们知道HashMap是一个常用的基于哈希表实现的工具类,底层是通过数组+链表(或红黑树)来实现的,它的读写复杂度是一个常量。今天的主角LinkedHashMap又提供了什么样的功能呢?

  1. 具有HashMap的所有功能和特点(它继承了HashMap)
  2. 能够保证内部元素访问的有序性(内部多实现了一个双向链表)

例子

下面我们通过一个例子了解下它的有序性吧。

// LinkedHashMap保证插入的有序性
Map<Integer, Integer> map = new LinkedHashMap<>();
map.put(1, 1);
map.put(3, 3);
map.put(2, 2);
map.put(4, 4);
map.get(3);//模拟访问
System.out.println("LinkedHashMap插入有序性:" + map.keySet());

// LinkedHashMap保证访问的有序性
map = new LinkedHashMap<>(16, 0.75f, true);
map.put(1, 1);
map.put(3, 3);
map.put(2, 2);
map.put(4, 4);
map.get(3);//模拟访问
System.out.println("LinkedHashMap访问有序性:" + map.keySet());

// HashMap内部实现基于其内部数组
map = new HashMap<>();
map.put(1, 1);
map.put(3, 3);
map.put(2, 2);
map.put(4, 4);
System.out.println("HashMap:" + map.keySet());

打印的日志如下:

LinkedHashMap插入有序性:[1, 3, 2, 4]
LinkedHashMap访问有序性:[1, 2, 4, 3]
HashMap:[1, 2, 3, 4]

上例中,第一段代码我们模拟了LinkedHashMap的插入有序性(LinkedHashMap默认为插入有序性模式),当通过LinkedHashMap的keySet、entrySet或values方法遍历其内部元素的时候,它能够保证插入元素的有序性;

第二代代码我们显式的指定了LinkedHashMap是访问有序的,并且看到key为3的元素在被访问到后打印在了最尾部;

第三段代码HashMap的这两个方法是基于其遍历其内部数组实现,而起内部数组上的槽点是基于key对象的hashCode确定的,所以针对不同类型的key对象,HashMap会给出不同的结果。

原理分析

LinkedHashMap内部实现了一个双向链表用来存储元素的插入顺序:

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

并且实现了三个迭代器用于keySet、entrySet或values方法遍历时,保证其内部元素有序性,它们都是从head节点开始遍历:

final class LinkedKeyIterator extends LinkedHashIterator
implements Iterator<K> {
  public final K next() { return nextNode().getKey(); }
}

final class LinkedValueIterator extends LinkedHashIterator
implements Iterator<V> {
  public final V next() { return nextNode().value; }
}

final class LinkedEntryIterator extends LinkedHashIterator
implements Iterator<Map.Entry<K,V>> {
  public final Map.Entry<K,V> next() { return nextNode(); }
}

那么LinkedHashMap是什么时候去更新这个双向链表的呢?在HashMap中有如下定义:

// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }

这几个方法就是为了支持LinkedHashMap在插入、删除、访问时及时更新其内部的双向链表的,LinkedHashMap也对这几个方法做了相应的实现,读者有兴趣可以去阅读下源码。

Demo地址


src/main/java/net/weichitech/collection/LinkedHashMapDemo.java · 小西学编程/java-learning - Gitee.com

相关文章

HashMap怎么学(一)

HashMap怎么学(二)数组扩容&链表生成

HashMap怎么学(三)红黑树

hashCode使用指南

TreeMap和红黑树