文章目录
声明:
本博客是本人在学习《Java 编程的逻辑》后整理的笔记,旨在方便复习和回顾,并非用作商业用途。
本博客已标明出处,如有侵权请告知,马上删除。
10.6 剖析 LinkedHashMap
之前我们介绍了 Map 接口的两个实现类 HashMap 和 TreeMap,本节来介绍另一个实现类 LinkedHashMap。它是 HashMap 的子类,但可以保持元素按插入或访问有序,这与 TreeMap 按键排序不同。
按插入有序容易理解,按访问有序是什么意思呢?这两个有序有什么用呢?内部是怎么实现的呢?本节就来探讨这些问题。从用法开始。
10.6.1 基本用法
LinkedHashMap 是 HashMap 的子类,但内部还有一个双向链表维护键值对的顺序,每个键值对既位于哈希表中,也位于这个双向链表中。
LinkedHashMap 支持两种顺序,一种是插入顺序,另外一种是访问顺序。
插入顺序容易理解,先添加的在前面,后添加的在后面,修改操作不影响顺序。
访问顺序是什么意思呢?所谓访问是指 get/put 操作,对一个键执行 get/put 操作后,其对应的键值对会移到链表末尾,所以,最末尾的是最近访问的,最开始的最久没被访问的,这种顺序就是访问顺序。
LinkedHashMap 有五个构造方法,其中四个都是按插入顺序,如下所示:
public LinkedHashMap()
public LinkedHashMap(int initialCapacity)
public LinkedHashMap(int initialCapacity, float loadFactor)
public LinkedHashMap(Map<? extends K, ? extends V> m)
只有一个构造方法,可以指定按访问顺序,如下所示:
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder)
其中参数 accessOrder 就是用来指定是否按访问顺序,如果为 true,就是访问顺序。
下面,我们通过一些简单的例子来看下。
10.6.1.1 按插入有序
默认情况下,LinkedHashMap 是按插入有序的,我们来看代码:
Map<String,Integer> seqMap = new LinkedHashMap<>();
seqMap.put("c", 100);
seqMap.put("d", 200);
seqMap.put("a", 500);
seqMap.put("d", 300);
for(Entry<String,Integer> entry : seqMap.entrySet()){
System.out.println(entry.getKey()+" "+entry.getValue());
}
键是按照 “c”, “d”, “a” 的顺序插入的,修改 “d” 的值不会修改顺序,所以输出为:
c 100
d 300
a 500
什么时候希望保持插入顺序呢?
Map 经常用来处理一些数据,其处理模式是,接受一些键值对作为输入,处理,然后输出,输出时希望保持原来的顺序。比如一个配置文件,其中有一些键值对形式的配置项,但其中有一些键是重复的,希望保留最后一个值,但还是按原来的键顺序输出,LinkedHashMap 就是一个合适的数据结构。
再比如,希望的数据模型可能就是一个 Map,但希望保持添加的顺序,比如一个购物车,键为购买项目,值为购买数量,按用户添加的顺序保存。
另外一种常见的场景是,希望 Map 能够按键有序,但在添加到 Map 前,键已经通过其他方式排好序了,这时,就没有必要使用 TreeMap 了,毕竟 TreeMap 的开销要大一些。比如,在从数据库查询数据放到内存时,可以使用 SQL 的 order by 语句让数据库对数据排序。
10.6.1.2 按访问有序
我们来看按访问有序的例子,代码如下:
Map<String,Integer> accessMap = new LinkedHashMap<>(16, 0.75f, true);
accessMap.put("c", 100);
accessMap.put("d", 200