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. hdu 2680 Choose the best route (dijkstra算法 最短路问题)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2680 Choose the best route Time Limit: 2000/1000 MS ( ...

  2. scikit-learn中的岭回归(Ridge Regression)与Lasso回归

    一.岭回归模型 岭回归其实就是在普通最小二乘法回归(ordinary least squares regression)的基础上,加入了正则化参数λ. 二.如何调用 class sklearn.lin ...

  3. 安全测试===sqlmap(肆)转载

    十八.杂项 1.使用简写 参数:-z 有些参数组合是被经常用到的,如“--batch --random-agent --ignore-proxy --technique=BEU”,这样写一大串很不好看 ...

  4. 64_k2

    kf5-libkdepim-akonadi-17.04.1-1.fc26.x86_64.rpm 25-May-2017 12:22 177198 kf5-libkdepim-devel-17.04.1 ...

  5. python string 对齐文本的几个方法

    用rjust().ljust()和center()方法对齐文本

  6. 微信小程序获取输入框(input)内容

    微信小程序---获取输入框(input)内容 wxml <input placeholder="请输入手机号码" maxlength="11" type= ...

  7. centos 6 编译安装php-5.4/5.5(lamp模式)

    在安装LAMP架构时,我们常用php-5.3的版本 现进行php-5.4/5.5的编译安装演示: [root@localhost ~]# cd /usr/local/src [root@localho ...

  8. 机器学习方法(四):决策树Decision Tree原理与实现技巧

    欢迎转载,转载请注明:本文出自Bin的专栏blog.csdn.net/xbinworld. 技术交流QQ群:433250724,欢迎对算法.技术.应用感兴趣的同学加入. 前面三篇写了线性回归,lass ...

  9. ubuntu上安装mysql及导入导出

    ubuntu上安装mysql:  1. sudo apt-get install mysql-server 2. apt-get isntall mysql-client3. sudo apt-get ...

  10. YII2源码阅读:autoload_real.php 22~23行

    spl_autoload_register(array('ComposerAutoloaderInit32b8eb537f8e12e57c5e7bade69d01f0', 'loadClassLoad ...