一、最基本元素存储单元

  1. /**
  2. * HashMap.Node subclass for normal LinkedHashMap entries.
  3. */
  4. static class Entry<K,V> extends HashMap.Node<K,V> {
  5. Entry<K,V> before, after;
  6. Entry(int hash, K key, V value, Node<K,V> next) {
  7. super(hash, key, value, next);
  8. }
  9. }
     还是原HashMap的,多了两个引用beforeafter,说明这是要用双向链表了

二、初始化 构造方法

  1. public LinkedHashMap() {
  2. super();
  3. accessOrder = false;
  4. }
  5. 多了 accessOrder = false;
  6.  
  7. /**
  8. * The iteration ordering method for this linked hash map: <tt>true</tt>
  9. * for access-order, <tt>false</tt> for insertion-order.
  10. *
  11. * @serial
  12. */
  13. final boolean accessOrder;
  14. accessOrder表示迭代顺序,true表示访问顺序,false表示插入顺序。

三、put方法

put方法没有重写,因此和HashMap是一样的,但也有不同,不同在于LinkedHashMap实现了afterNodeAccess,afterNodeInsertion方法
看HashMap put源码

  1. final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
  2. boolean evict) {
  3. Node<K,V>[] tab; Node<K,V> p; int n, i;
  4. if ((tab = table) == null || (n = tab.length) == 0)
  5. n = (tab = resize()).length;
  6. if ((p = tab[i = (n - 1) & hash]) == null)
  7. tab[i] = newNode(hash, key, value, null);
  8. else {
  9. Node<K,V> e; K k;
  10. if (p.hash == hash &&
  11. ((k = p.key) == key || (key != null && key.equals(k))))
  12. e = p;
  13. else if (p instanceof TreeNode)
  14. e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
  15. else {
  16. for (int binCount = 0; ; ++binCount) {
  17. if ((e = p.next) == null) {
  18. p.next = newNode(hash, key, value, null);
  19. if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
  20. treeifyBin(tab, hash);
  21. break;
  22. }
  23. if (e.hash == hash &&
  24. ((k = e.key) == key || (key != null && key.equals(k))))
  25. break;
  26. p = e;
  27. }
  28. }
  29. if (e != null) { // existing mapping for key
  30. V oldValue = e.value;
  31. if (!onlyIfAbsent || oldValue == null)
  32. e.value = value;
  33. afterNodeAccess(e); //这个方法HashMap是空实现,这里是发生hash冲突后,找到有相同key对值进行处理时调用
  34. return oldValue;
  35. }
  36. }
  37. ++modCount;
  38. if (++size > threshold)
  39. resize();
  40. afterNodeInsertion(evict); //这个方法HashMap也是空实现,这里是完成新数据put后调用
  41. return null;
  42. }
  1. LinkedHashMap具体实现 :
  2. 1.void afterNodeAccess(Node<K,V> e) { // move node to last 注释就说明了是把该元素移到最后
  3. LinkedHashMap.Entry<K,V> last;
  4. if (accessOrder && (last = tail) != e) { //accessOrder用到了,默认false等于不运行,true时是按插入顺序
  5. LinkedHashMap.Entry<K,V> p =
  6. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  7. p.after = null;
  8. if (b == null)
  9. head = a;
  10. else
  11. b.after = a;
  12. if (a != null)
  13. a.before = b;
  14. else
  15. last = b;
  16. if (last == null)
  17. head = p;
  18. else {
  19. p.before = last;
  20. last.after = p;
  21. }
  22. tail = p;
  23. ++modCount;
  24. }
  25. }
  26. 以上代码看出在按插入顺序时,在有相同key时,对当前节点将其移到链表末尾
  27.  
  28. 2.void afterNodeInsertion(boolean evict) { // possibly remove eldest
  29. LinkedHashMap.Entry<K,V> first;
  30. if (evict && (first = head) != null && removeEldestEntry(first)) {
  31. K key = first.key;
  32. removeNode(hash(key), key, null, false, true);
  33. }
  34. }
  35. removeEldestEntry 方法在jdk1.8中固定返回false,因此不用关注此方法
  36. 说明一下removeElestEntry用于定义删除最老元素的规则。一旦需要删除最老节点,那么将会调用removeNode删除节点。
    举个例子,如果一个链表只能维持100个元素,那么当插入了第101个元素时,以如下方式重写removeEldestEntry的话,那么将会删除最老的一个元素
  1.  

 四、get方法(get进行了重写) ,在插入模式中,获取值后又一次进行把当前节点移到链表尾部操作

  有点类似LRU(最少最近使用)算法~

  1. /*基于访问排序*/
  2. LinkedHashMap<String, String> linkedHashMap_accessOrder = new LinkedHashMap<>(10,0.75f,true);
  3. linkedHashMap_accessOrder.put("name1", "josan1");
  4. linkedHashMap_accessOrder.put("name2", "josan2");
  5. linkedHashMap_accessOrder.put("name3", "josan3");
  6. linkedHashMap_accessOrder.put("name4", "josan4");
  7. linkedHashMap_accessOrder.put("name5", "josan5");
  8.  
  9. linkedHashMap_accessOrder.get("name5");
  10. linkedHashMap_accessOrder.get("name1");
  11. linkedHashMap_accessOrder.get("name2");
  12. linkedHashMap_accessOrder.get("name4");
  13. linkedHashMap_accessOrder.get("name3");
  14. //51243顺序
  15. for (Map.Entry<String, String> entry : linkedHashMap_accessOrder.entrySet()) {
  16. String key = entry.getKey();
  17. String value = entry.getValue();
  18. System.out.println("key:" + key + ",value:" + value);
  19. }

get方法: (accessOrder 为true表示按照访问排序),

  1. public V get(Object key) {
  2. Node<K,V> e;
  3. if ((e = getNode(hash(key), key)) == null)
  4. return null;
  5. if (accessOrder)
  6. afterNodeAccess(e);
  7. return e.value;
  8. }

将节点移动到最后:

  1. void afterNodeAccess(Node<K,V> e) { // move node to last
  2. LinkedHashMap.Entry<K,V> last;
  3. if (accessOrder && (last = tail) != e) {
  4. LinkedHashMap.Entry<K,V> p =
  5. (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
  6. p.after = null;
  7. if (b == null)
  8. head = a;
  9. else
  10. b.after = a;
  11. if (a != null)
  12. a.before = b;
  13. else
  14. last = b;
  15. if (last == null)
  16. head = p;
  17. else {
  18. p.before = last;
  19. last.after = p;
  20. }
  21. tail = p;
  22. ++modCount;
  23. }
  24. }

层层判断和更改引用之后,p已经独立出来了,就把p移到了map的末尾,实现了访问排序

总结

1. HashMap中TreeNode 即红黑树的节点类是继承LinkedHashMap.Entry

2. HashMap中没有使用双向链表,before, after没有使用,单纯的红黑树

3.LinkedHashMap是HashMap的子类,很多方法都是继承自父类,

LinkedHashMap中,存取等使用的也使用红黑树,但维护了before, after的链表属性,在存取时一样使用红黑树算法,

但keySet()、values()以及entrySet()等迭代时使用的是双向链表来进行的,这样的双向链表结构保证了插入顺序的有序。

4.总得来说,LinkedHashMap底层是数组加单项链表加双向链表。

5.数组加单向链表就是HashMap的结构,记录数据用,双向链表,存储插入顺序用。然后LInkedHashMap重写了两个方法,一个是添加entry,一个是创建entry,这两种时刻都要维护双向链表。

参考出处:https://www.cnblogs.com/zhaojj/p/7832680.html

LinkedHashMap笔记的更多相关文章

  1. jdk源码阅读笔记-LinkedHashMap

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

  2. java集合类学习笔记之LinkedHashMap

    1.简述 LinkedHashMap是HashMap的子类,他们最大的不同是,HashMap内部维护的是一个单向的链表数组,而LinkedHashMap内部维护的是一个双向的链表数组.HashMap是 ...

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

    HashMap有一个问题,就是迭代HashMap的顺序并不是HashMap放置的顺序,也就是无序. LinkedHashMap保证了元素迭代的顺序.该迭代顺序可以是插入顺序或者是访问顺序.通过维护一个 ...

  4. Java TreeMap 和 LinkedHashMap【笔记】

    Java TreeMap 和 LinkedHashMap[笔记] TreeMap TreeMap基本结构 TreeMap 底层的数据结构就是红黑树,和 HashMap 的红黑树结构一样 与HashMa ...

  5. LinkedHashMap源码阅读笔记(基于jdk1.8)

    LinkedHashMap是HashMap的子类,很多地方都是直接引用HashMap中的方法,所以需要注意的地方并不多.关键的点就是几个重写的方法: 1.Entry是继承与Node类,也就是Linke ...

  6. HashMap LinkedHashMap源码分析笔记

    MapClassDiagram

  7. 【Java学习笔记】HashMap子接口---LinkedHashMap

    特点: 存入元素的顺序   与   取出元素的顺序相同(与LinkedHashSet类似) import java.util.HashMap; import java.util.Iterator; i ...

  8. Java基础知识强化之集合框架笔记58:Map集合之LinkedHashMap类的概述

    1. LinkedHashMap类的概述 LinkedHashMap:Map接口的哈希表(保证唯一性) 和 链接(保证有序性)列表实现,具有可预知的迭代顺序. 2. 代码示例: package cn. ...

  9. Java笔记(八)TreeMap & TreeSet & LinkedHashMap

    TreeMap & TreeSet & LinkedHashMap 一.TreeMap HashMap缺陷:键值对之间没有特定的顺序.在TreeMap中, 键值对之间按键有序,Tree ...

随机推荐

  1. ionic-Javascript:ionic 上拉菜单(ActionSheet)

    ylbtech-ionic-Javascript:ionic 上拉菜单(ActionSheet) 1.返回顶部 1. ionic 上拉菜单(ActionSheet) 上拉菜单(ActionSheet) ...

  2. 20140319 const sizeof define 编译时分配内存

    1.面试宝典预处理,const,sizeof Define作用定义函数: //用一个宏定义FIND求一个结构体struc里某个变量相对于struc的偏移量,如FIND(student,a)//等于0 ...

  3. 【6折抢】戴尔i7新品Latitude高性能商用本

    致敬拼搏成长中的企业 戴尔5月有钜惠! 买1赠1送同款,单台价格2500元 这波来自戴尔官网的致敬很走心 满足初级办公和高性能运算多重需求 限时折扣火热开抢! 新品  latitude 6折抢! 戴尔 ...

  4. Git仓库操作命令

    创建仓库 git init 在当前目录执行,会生成.git目录文件,这个和SVN一致. 提交到仓库 git commit -m "first commit" -m:表示提交描述,必 ...

  5. java-day13

    异常 指的是程序在执行过程中,出现的非正常情况,最终会导致JVM的非正常停止 异常分类:编译异常,运行期异常 异常的产生过程分析 throw关键字:指方法中抛出指定异常 使用格式:throw new ...

  6. 调用第三方jar包_md5加密

    vars.put是转换成jmeter格式

  7. 免费的高分辨率图库——re:splashed 可用做网页背景、设计或桌面壁纸

    想找高清图片用作网站背景.设计或桌面壁纸?可以去re:splashed看看.re:splashed 是一个提供免费高分辨率HD图片的网站,有多种分类标签,查找很方便,无需注册和登陆便可下载. 网站名称 ...

  8. js 实现多选

    效果: html: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...

  9. .net中的泛型全面解析

    从2.0起我们一直就在谈论泛型,那么什么是泛型,泛型有什么好处,与泛型相关的概念又该怎么使用,比如泛型方法,泛型委托.这一篇我会全面的介绍泛型. 那么首先我们必须搞清楚什么是泛型,泛型其实也是一种类型 ...

  10. python 取出aws中ip有,zabbix中没有的ip

    #!/usr/bin/env python3# coding=utf-8import requestsimport jsonimport boto3 headers = {'Content-Type' ...