1.概述

在理解了#7 介绍的HashMap后,我们来学习LinkedHashMap的工作原理及实现。首先还是类似的,我们写一个简单的LinkedHashMap的程序:

LinkedHashMap<String, Integer> lmap = new LinkedHashMap<String, Integer>();
lmap.put("语文", 1);
lmap.put("数学", 2);
lmap.put("英语", 3);
lmap.put("历史", 4);
lmap.put("政治", 5);
lmap.put("地理", 6);
lmap.put("生物", 7);
lmap.put("化学", 8);
for(Entry<String, Integer> entry : lmap.entrySet()) {
System.out.println(entry.getKey() + ": " + entry.getValue());
}

运行结果是:

语文: 1
数学: 2
英语: 3
历史: 4
政治: 5
地理: 6
生物: 7
化学: 8

我们可以观察到,和HashMap的运行结果不同,LinkedHashMap的迭代输出的结果保持了插入顺序。是什么样的结构使得LinkedHashMap具有如此特性呢?我们还是一样的看看LinkedHashMap的内部结构,对它有一个感性的认识:

没错,正如官方文档所说:

Hash table and linked list implementation of the Map interface, with predictable iteration order. This implementation differs from HashMap in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is normally the order in which keys were inserted into the map (insertion-order).

LinkedHashMap是Hash表和链表的实现,并且依靠着双向链表保证了迭代顺序是插入的顺序。

2. 三个重点实现的函数

在HashMap中提到了下面的定义:

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

LinkedHashMap继承于HashMap,因此也重新实现了这3个函数,顾名思义这三个函数的作用分别是:节点访问后、节点插入后、节点移除后做一些事情。

afterNodeAccess函数

void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
// 如果定义了accessOrder,那么就保证最近访问节点放到最后
if (accessOrder && (last = tail) != e) {
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a != null)
a.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}

就是说在进行put之后就算是对节点的访问了,那么这个时候就会更新链表,把最近访问的放到最后,保证链表。

afterNodeInsertion函数

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);
}
}

如果用户定义了removeEldestEntry的规则,那么便可以执行相应的移除操作。

afterNodeRemoval函数

void afterNodeRemoval(Node<K,V> e) { // unlink
// 从链表中移除节点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
p.before = p.after = null;
if (b == null)
head = a;
else
b.after = a;
if (a == null)
tail = b;
else
a.before = b;
}

这个函数是在移除节点后调用的,就是将节点从双向链表中删除。

我们从上面3个函数看出来,基本上都是为了保证双向链表中的节点次序或者双向链表容量所做的一些额外的事情,目的就是保持双向链表中节点的顺序要从eldest到youngest。

3. put和get函数

put函数在LinkedHashMap中未重新实现,只是实现了afterNodeAccess和afterNodeInsertion两个回调函数。get函数则重新实现并加入了afterNodeAccess来保证访问顺序,下面是get函数的具体实现:

public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}

值得注意的是,在accessOrder模式下,只要执行get或者put等操作的时候,就会产生structural modification。官方文档是这么描述的:

A structural modification is any operation that adds or deletes one or more mappings or, in the case of access-ordered linked hash maps, affects iteration order. In insertion-ordered linked hash maps, merely changing the value associated with a key that is already contained in the map is not a structural modification. In access-ordered linked hash maps, merely querying the map with get is a structural modification.

不要犯了像ConcurrentModificationException with LinkedHashMap类似的问题。

总之,LinkedHashMap不愧是HashMap的儿子,和老子太像了,当然,青出于蓝而胜于蓝,LinkedHashMap的其他的操作也基本上都是为了维护好那个具有访问顺序的双向链表。

[Java]LinkedHashMap实现原理的更多相关文章

  1. Java LinkedHashMap工作原理及实现

    Java LinkedHashMap工作原理及实现 原文出处: Yikun 1. 概述 在理解了#7 介绍的HashMap后,我们来学习LinkedHashMap的工作原理及实现.首先还是类似的,我们 ...

  2. java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现

    java基础解析系列(四)---LinkedHashMap的原理及LRU算法的实现 java基础解析系列(一)---String.StringBuffer.StringBuilder java基础解析 ...

  3. Java HashMap工作原理及实现

    Java HashMap工作原理及实现 2016/03/20 | 分类: 基础技术 | 0 条评论 | 标签: HASHMAP 分享到:3 原文出处: Yikun 1. 概述 从本文你可以学习到: 什 ...

  4. 6 手写Java LinkedHashMap 核心源码

    概述 LinkedHashMap是Java中常用的数据结构之一,安卓中的LruCache缓存,底层使用的就是LinkedHashMap,LRU(Least Recently Used)算法,即最近最少 ...

  5. 了解一下Java SPI的原理

    了解一下Java SPI的原理 1 为什么写这篇文章? 近期,本人在学习dubbo相关的知识,但是在dubbo官网中有提到Java的 SPI,这个名词之前未接触过,所以就去看了看,感觉还是有很多地方有 ...

  6. 深入Java核心 Java内存分配原理精讲

    深入Java核心 Java内存分配原理精讲 栈.堆.常量池虽同属Java内存分配时操作的区域,但其适用范围和功用却大不相同.本文将深入Java核心,详细讲解Java内存分配方面的知识. Java内存分 ...

  7. paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换

    paip.java UrlRewrite 的原理and实现 htaccess正则表达式转换 #---KEYWORD #-正则表达式 正则表达式 表示 非指定字符串开头的正则 排除指定目录.. 作者 老 ...

  8. Java虚拟机工作原理详解 (一)

    一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了解java程序工作原理.首先,你写好java代码,保存到硬盘当中.然后你在命令行中输入 javac YourClassNam ...

  9. Java虚拟机工作原理详解

    原文地址:http://blog.csdn.net/bingduanlbd/article/details/8363734 一.类加载器 首先来看一下java程序的执行过程. 从这个框图很容易大体上了 ...

随机推荐

  1. 基于对话框的Opengl框架

    转自:http://blog.csdn.net/longxiaoshi/article/details/8238933 12-11-29 14:55 1198人阅读 评论(6) 收藏 举报  分类: ...

  2. CATTI二级口译训练

    Vice chancellor, faculty members and dear students, It is my great pleasure and privilege to visit C ...

  3. C语言中的文件操作

    按照字符的方式读取文件 按照行的方式读取文件 按照数据块的方式读取文件 按照格式化的方式读取文件 文件分类 记录文件:具有一定的结构记录组成,分为定长和不定长两种方式 流式文件:按照一个字符一个字符( ...

  4. ACM学习历程—HDU2222 Keywords Search(字典树)

    Keywords Search Description In the modern time, Search engine came into the life of everybody like G ...

  5. [转载]IOCP模型的总结

    原文:IOCP模型的总结 IOCP(I/O Completion Port,I/O完成端口)是性能最好的一种I/O模型.它是应用程序使用线程池处理异步I/O请求的一种机制.在处理多个并发的异步I/O请 ...

  6. drop asm disk、撤销drop asm disk

    drop asm disk.撤销drop asm disk drop asm disk:SQL> alter diskgroup XXX offline disk XXXX drop after ...

  7. 单机11g ogg 双向DML复制

    环境说明: Linux为Linux 2.6.32-573.el6.x86_64 Oracle为 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Pr ...

  8. sum(sum(abs(y))) 中 sum(sum())什么意思?

    >> y=[1 3;2 5] y =      1     3      2     5 >> sum(y) ans =      3     8 >> sum(s ...

  9. [CentOS] 结合Nginx部署DotNetCore的demo项目【转载】

    部署前准备 1.VisualStudio2017+.netcore2.0SDK 2.Centos7.2 3.SecureCRT,Xftp(根据自己喜好) 创建WebApi项目 修改Program.cs ...

  10. [hiho1584]Bounce

    题意:找出图中经过一次的格子个数. 解题关键: 组合数学的思想:先找出总的经过格子的次数,然后减去2倍的经过2次的格子个数. 1.总的求法:将长延展,当延展到n倍时,能够恰好到达右边的两个端点,则总格 ...