HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序。

LinkedHashMap保证了元素迭代的顺序。该迭代顺序可以是插入顺序或者是访问顺序。通过维护一个双向链表实现。

需要在理解HashMap实现原理的基础上学习LinkedHashMap,JDK源码学习笔记——HashMap

一、数据结构

实际上就是在HashMap的基础上加了LinkedList

(图片来自Java集合之LinkedHashMap

LinkedHashMap.Entry继承了HashMap.Node,并扩展了before ,after属性

    static class Entry<K,V> extends HashMap.Node<K,V> {
Entry<K,V> before, after;
Entry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}

二、类

继承了HashMap

public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>

三、属性

    transient LinkedHashMap.Entry<K,V> head;
transient LinkedHashMap.Entry<K,V> tail;
final boolean accessOrder;//true表示按照访问顺序迭代(最近访问在后),false时表示按照插入顺序(先插入在前,默认)

四、主要方法

put

    /**
* 直接使用HashMap的put方法
* 重写了newNode()方法:维护双向链表
* 重写了afterNodeAccess(e)方法:如果按访问顺序排序,把node移动到双链表的尾端
*/
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
LinkedHashMap.Entry<K,V> p =
new LinkedHashMap.Entry<K,V>(hash, key, value, e);
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;
}
} void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
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;
}
}

get

    /**
* 重写了get方法
* 如果按访问顺序排序,把node移动到双链表的尾端
*/
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
if (accessOrder)
afterNodeAccess(e);// 如果按访问顺序排序,把node移动到双链表的尾端
return e.value;
}

remove

    /**
* 直接使用HashMap的remove方法
* 重写了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;
}

遍历

    /**
* 主要看nextNode()方法
* 直接遍历的双向链表
*/
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();
}
} abstract class LinkedHashIterator {
LinkedHashMap.Entry<K,V> next;
LinkedHashMap.Entry<K,V> current;
int expectedModCount; LinkedHashIterator() {
next = head;
expectedModCount = modCount;
current = null;
} public final boolean hasNext() {
return next != null;
} final LinkedHashMap.Entry<K,V> nextNode() {
LinkedHashMap.Entry<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;
return e;
} public final void remove() {
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}

JDK源码学习笔记——LinkedHashMap的更多相关文章

  1. jdk源码阅读笔记-LinkedHashMap

    Map是Java collection framework 中重要的组成部分,特别是HashMap是在我们在日常的开发的过程中使用的最多的一个集合.但是遗憾的是,存放在HashMap中元素都是无序的, ...

  2. JDK源码学习笔记——String

    1.学习jdk源码,从以下几个方面入手: 类定义(继承,实现接口等) 全局变量 方法 内部类 2.hashCode private int hash; public int hashCode() { ...

  3. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  4. JDK源码学习笔记——Enum枚举使用及原理

    一.为什么使用枚举 什么时候应该使用枚举呢?每当需要一组固定的常量的时候,如一周的天数.一年四季等.或者是在我们编译前就知道其包含的所有值的集合. 利用 public final static 完全可 ...

  5. JDK源码学习笔记——Object

    一.源码解析 public class Object { /** * 一个本地方法,具体是用C(C++)在DLL中实现的,然后通过JNI调用 */ private static native void ...

  6. JDK源码学习笔记——HashMap

    Java集合的学习先理清数据结构: 一.属性 //哈希桶,存放链表. 长度是2的N次方,或者初始化时为0. transient Node<K,V>[] table; //最大容量 2的30 ...

  7. JDK源码学习笔记——HashSet LinkedHashSet TreeSet

    你一定听说过HashSet就是通过HashMap实现的 相信我,翻一翻HashSet的源码,秒懂!! 其实很多东西,只是没有静下心来看,只要去看,说不定一下子就明白了…… HashSet 两个属性: ...

  8. JDK源码学习笔记——TreeMap及红黑树

    找了几个分析比较到位的,不再重复写了…… Java 集合系列12之 TreeMap详细介绍(源码解析)和使用示例 [Java集合源码剖析]TreeMap源码剖析 java源码分析之TreeMap基础篇 ...

  9. JDK源码学习笔记——LinkedList

    一.类定义 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E& ...

随机推荐

  1. 【Windows使用笔记】使Onedrive同步任意文件夹

    因为度盘实在是有点垃圾,经常看的剧之类的或者其他软件资源啥的动不动就被封. 所以跑去某宝买了一个5T的企业子账号,安全性不清楚,重要的隐私数据反正都用移动硬盘备份了.主要就是存一些资源性的文件吧.而且 ...

  2. 浅析linux内核中timer定时器的生成和sofirq软中断调用流程【转】

    转自:http://blog.chinaunix.net/uid-20564848-id-73480.html 浅析linux内核中timer定时器的生成和sofirq软中断调用流程 mod_time ...

  3. 使用makecontext实现用户线程【转】

    转自:http://blog.csdn.net/cyberlabs/article/details/6920138 使用makecontext实现用户线程 现代Unix系统都在ucontext.h中提 ...

  4. 在64位linux下编译32位程序

    在64位linux下编译32位程序 http://blog.csdn.net/xsckernel/article/details/38045783

  5. OGRECave [www]

    OGRECave https://github.com/OGRECave

  6. spark 环境搭建坑

    spark的新人会有什么坑 spark是一个以java为基础的,以Scala实现的,所以在你在安装指定版本的spark,需要检查你用的是对应spark使用什么版本的scala,可以通过spark-sh ...

  7. SQL 列 转换成 查询出来的 行

    查询  每个学生 的  (姓名,语文,数学,英语,成绩)为列 表结构如下: student: 学生表 grade 成绩表 : 查询出如下效果: SQL如下: select s.name,a.* fro ...

  8. debian下没有公钥解决办法

    debian下没有公钥解决办法   执行命令:apt-get update  出现如下错误   正在读取软件包列表... 完成   W: 以下 ID 的密钥没有可用的公钥: 8B48AD6246925 ...

  9. spring使用aop需要的jar包,和常见异常

    3.0以后spring不再一起发布aop依赖包,需要自己导入: 必须包: 这几个jar包分别为 1.org.springframework.aop-3.1.1.RELEASE  这个是spring的 ...

  10. jstree无限级菜单ajax按需动态加载子节点

    业余时间研究了一下jstree,更新非常快已经是3.0了,首先看一下效果截图: 1.页面引入样式和脚本(注意路径根据实际情况) <link href="~/Scripts/vakata ...