了解 LinkedHashMap
本文共2618字,阅读本文大概需要5~9分钟
原理
- LinkedHashMap,会记录你插入的 key-value 的顺序,如果你遍历的时候,它是按照插入的 key-value 对的顺序遍历出来的
- LinkedHashMap 是 HashMap 的一个子类,与 TreeMap 的区别是,他们都可以维持 key 的顺序,只是 LinkedHashMap 底层是基于链表来实现的,TreeMap 是基于红黑树来实现顺序的
- LinkedHashMap 其实原则上来说一些基本的原理和操作跟 HashMap是差不多的,唯一主要的区别就是在插入、覆盖、删除的时候,它会记录一下 key-value 对的顺序,用一个链表来记录,在遍历的时候,就可以按照这个顺序来遍历了
基本操作
public static void main(String[] args) {
Map<Integer, String> map = new LinkedHashMap<>();
map.put(2,"张三");
map.put(1,"李四");
map.put(3,"王五");
map.remove(2);
map.put(1,"ls");
for(Map.Entry<Integer, String> entry : map.entrySet()){
System.out.println(entry.getKey()+"--->"+entry.getValue());
}
}
#######################
输出:
1--->ls
3--->王五
Map的遍历
- 方法一
for(Map.Entry<Integer, String> entry : map.entrySet()){
System.out.println(entry.getKey()+"--->"+entry.getValue());
}
- 方法二
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<Integer, String> entry = (Map.Entry<Integer, String>) it.next();
System.out.println(entry.getKey()+"=="+entry.getValue());
}
- 方法三
Iterator<Integer> its = map.keySet().iterator();
while (its.hasNext()) {
Integer key = its.next();
System.out.println(key + "==" + map.get(key));
}
- 方法四
Set set = map.entrySet();
Iterator i = set.iterator();
while(i.hasNext()){
Map.Entry<Integer, String> entry1=(Map.Entry<Integer, String>)i.next();
System.out.println(entry1.getKey()+"=="+entry1.getValue());
}
put()方法
在调用LinkedHashMap的 put() 方法的时候,一定会调用到 HashMap的 put() 方法里面去,调用完 put() 方法,插入一个 key-value 对之后,其实就会调用 afterNodeInsertion(evict) 这个方法去回调 LinkedHashMap 里面子类的实现
void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
调用下面这个方法,其实它就是实现了 LinkedHashMap 的逻辑,用来记录插入 key-value 对的顺序,用一个链表来记录
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
// 将节点封装为了一个LinkedHashMap.Entry对象
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
// 使用linkNodeLast(p)这个东西,将这个节点挂到一个链表里去
linkNodeLast(p);
return p;
}
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
关于值的覆盖
如果我们要做对 key 值的覆盖,可以看到,你多次覆盖一个值,不会改变它的顺序,LinkedHashMap 有一个参数,你可以在构造的时候传入进去,accessOrder,这个值默认为 false,如果是默认为 false 的话,那么当你 get 一个key,或者是覆盖这个key的值,都不会改变它在链表里的顺序
但是如果 accessOrder 是 true 的话,那么当你get一个key,或者覆盖这个key的值,就会导致这个 key-value 对顺序会在链表里改变,他会被挪动到链表的尾部去,如果你把accessOrder 指定为true,你每次修改一个key的值或者是get一个这个key,都会导致这个key挪动到尾部去
你删除某个元素的时候,就会将那个元素从链表中摘除
在迭代的时候,LinkedHashMap里面会从链表的头部开始迭代,这样通过这个链表就可以维持他的一个顺序
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南