TreeMap是一颗红黑树做Map。HashMap是数组+链表+红黑树。HashTable是数组+链表。

LinkedHashMap底层存储结构与HashMap一样,不同的是LinkedHashMap增加了一个双向链表的头节点,插入的数据除了插入HashMap,还会插入链表中,因而可以保存插入节点的顺序

LinkedHashMap的节点在HashMap节点的基础上增加了前后节点的引用

LinkedHashMap相比HashMap在查找值和删除值时效率要高

LinkedHashMap还可以设置按插入顺序排序或是按访问顺序排序,默认是按插入顺序排序

LinkedHashMap没有put方法,而是覆写了afterNodeAccess方法和afterNodeInsertion方法。当插入的数据已经存在时,会调用afterNodeAccess方法看是否需要将数据插入到链表末尾;当插入的数据是新数据时,会通过afterNodeInsertion方法来根据设置删除近期使用最少的节点

LinkedHashMap可以用来实现LRU算法。首先需要用可以设置accessOrder的构造函数设置accessOrder为true,也就是按照节点访问顺序排序;

而LinkedHashMap还拥有HashMap一样的结构,原因在于其继承自HashMap,因此HashMap中用于存储元素的table也被继承过来,于是乎元素的存储也具备和HashMap一样的规则,所有元素存储在table中,table下的每个索引在原HashMap的结构下也是一个单向链表,同时每个元素中额外增加的before和after引用将table中的元素互连起来。

HashMap链表节点:next,

HashMap红黑树节点TreeNode:parent,left,right,prev,next, 

LinkedHashMap链表节点:before,after,next, 

LinkedHashMap跟HashMap一样,只不过增加了head,tail把所有元素串联起来了。

  1. public class testLinkedHashMap1 {
  2. @SuppressWarnings({ "rawtypes", "unchecked" })
  3. public static void main(String[] args) {
  4. LinkedHashMap1<Integer,String> hh = new LinkedHashMap1<Integer,String>();
  5.  
  6. //链表添加
  7. hh.put(, "");//放到LinkedHashMap1的table[0]中,此时是链表(节点有next没有after,before)
  8. hh.put(, "");
  9. // hh.remove(4);//链表删除
  10. // hh.put(4, "4");
  11. hh.put(, "");
  12. hh.put(, "");//0位置转成红黑树
  13. hh.put(, "");
  14. hh.put(, "");
  15. hh.put(, "");
  16. hh.put(, "");//1位置链表添加
  17. hh.put(, "");
  18. hh.put(, "");
  19.  
  20. hh.get();
  21.  
  22. Set s = hh.keySet();//[0, 16, 32, 48, 54, 60, 76, 1, 2, 3]
  23. Iterator i = s.iterator();
  24. if(i.hasNext()) System.out.println(i.next());
  25. // i.remove();
  26. if(i.hasNext()) System.out.println(i.next());
  27.  
  28. }
  29. }
  1. //extends HashMap1,table也被继承过来,数组+链表+红黑树。
  2. public class LinkedHashMap1<K, V> extends HashMap1<K, V> implements Map1<K, V> {
  3. private static final long serialVersionUID = 3801124242820219131L;
  4. transient LinkedHashMap1.Entry<K, V> head;// 双向链表的头节点和尾节点
  5. transient LinkedHashMap1.Entry<K, V> tail;
  6. final boolean accessOrder;// true,使用节点之后就把节点放到最末尾。false就不放。用于删除第一个最不常用的元素。
  7.  
  8. private void linkNodeLast(LinkedHashMap1.Entry<K, V> p) {// 链表末尾添加,有before,after
  9. LinkedHashMap1.Entry<K, V> last = tail;//保留原来的tail
  10. tail = p;//修改tail
  11. if (last == null)// tail=null
  12. head = p;// tail = head = p
  13. else {
  14. p.before = last;
  15. last.after = p;
  16. }
  17. }
  18.  
  19. // dst替换src
  20. private void transferLinks(LinkedHashMap1.Entry<K, V> src, LinkedHashMap1.Entry<K, V> dst) {
  21. LinkedHashMap1.Entry<K, V> b = dst.before = src.before;
  22. LinkedHashMap1.Entry<K, V> a = dst.after = src.after;
  23. if (b == null)// 替换的src是第一个节点
  24. head = dst;
  25. else
  26. b.after = dst;
  27. if (a == null)// 替换的src是最后一个节点
  28. tail = dst;
  29. else
  30. a.before = dst;
  31. }
  32.  
  33. public void reinitialize() {
  34. super.reinitialize();// table = null; entrySet = null; keySet = null; values = null;
  35. head = tail = null;
  36. }
  37. //生成一个节点(链表中的节点,不是红黑树中的节点,有hash, key, value, next没有before,after)
  38. public Node<K, V> newNode(int hash, K key, V value, Node<K, V> e) {//
  39. LinkedHashMap1.Entry<K, V> p = new LinkedHashMap1.Entry<K, V>(hash, key, value, e);
  40. linkNodeLast(p);// 生成新的节点并插入到尾部
  41. return p;
  42. }
  43.  
  44. public Node<K, V> replacementNode(Node<K, V> p, Node<K, V> next) {
  45. LinkedHashMap1.Entry<K, V> q = (LinkedHashMap1.Entry<K, V>) p;
  46. LinkedHashMap1.Entry<K, V> t = new LinkedHashMap1.Entry<K, V>(q.hash, q.key, q.value, next);
  47. transferLinks(q, t);// t替换q
  48. return t;
  49. }
  50.  
  51. public TreeNode<K, V> newTreeNode(int hash, K key, V value, Node<K, V> next) {
  52. TreeNode<K, V> p = new TreeNode<K, V>(hash, key, value, next);
  53. linkNodeLast(p);// 末尾添加p
  54. return p;
  55. }
  56.  
  57. public TreeNode<K, V> replacementTreeNode(Node<K, V> p, Node<K, V> next) {
  58. LinkedHashMap1.Entry<K, V> q = (LinkedHashMap1.Entry<K, V>) p;
  59. TreeNode<K, V> t = new TreeNode<K, V>(q.hash, q.key, q.value, next);
  60. transferLinks(q, t);// t替换q
  61. return t;
  62. }
  63.  
  64. public void afterNodeRemoval(Node<K, V> e) { // 删除节点e
  65. LinkedHashMap1.Entry<K, V> p = (LinkedHashMap1.Entry<K, V>) e, b = p.before, a = p.after;
  66. p.before = p.after = null;
  67. if (b == null)
  68. head = a;
  69. else
  70. b.after = a;
  71. if (a == null)
  72. tail = b;
  73. else
  74. a.before = b;
  75. }
  76.  
  77. public void afterNodeInsertion(boolean evict) { // 添加新的节点时候,有可能删除最老的元素
  78. LinkedHashMap1.Entry<K, V> first;
  79. if (evict && (first = head) != null && removeEldestEntry(first)) {
  80. K key = first.key;// 删除第一个元素,每次使用元素之后,就会把元素放到最末尾,第一个元素就是最少使用的元素。
  81. removeNode(hash(key), key, null, false, true);// hashMap方法,
  82. }
  83. }
  84.  
  85. public void afterNodeAccess(Node<K, V> e) { // 节点e被修改后,e不是尾节点(e是尾节点就不动),把e节点移到最后。
  86. LinkedHashMap1.Entry<K, V> last;
  87. if (accessOrder && (last = tail) != e) {
  88. LinkedHashMap1.Entry<K, V> p = (LinkedHashMap1.Entry<K, V>) e, b = p.before, a = p.after;
  89. p.after = null;// 多个属性指向同一地址值,只是修改其中一个的地址值,其余不变。
  90.  
  91. if (b == null)
  92. head = a;//
  93. else
  94. b.after = a;
  95.  
  96. if (a != null)
  97. a.before = b;
  98. else
  99. last = b;//
  100.  
  101. if (last == null)
  102. head = p;
  103. else {
  104. p.before = last;
  105. last.after = p;
  106. }
  107. tail = p;
  108. ++modCount;
  109. }
  110. }
  111.  
  112. public void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
  113. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after) {
  114. s.writeObject(e.key);
  115. s.writeObject(e.value);
  116. }
  117. }
  118.  
  119. public LinkedHashMap1(int initialCapacity, float loadFactor) {
  120. super(initialCapacity, loadFactor);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
  121. accessOrder = false;// true,使用节点之后就把节点放到最末尾。false就不放。
  122. }
  123.  
  124. public LinkedHashMap1(int initialCapacity) {
  125. super(initialCapacity);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
  126. accessOrder = false;
  127. }
  128.  
  129. public LinkedHashMap1() {
  130. super();// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
  131. accessOrder = false;
  132. }
  133.  
  134. public LinkedHashMap1(Map1<? extends K, ? extends V> m) {
  135. super();// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
  136. accessOrder = false;
  137. putMapEntries(m, false);
  138. }
  139.  
  140. public LinkedHashMap1(int initialCapacity, float loadFactor, boolean accessOrder) {
  141. super(initialCapacity, loadFactor);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
  142. this.accessOrder = accessOrder;
  143. }
  144.  
  145. public boolean containsValue(Object value) {
  146. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after) {
  147. V v = e.value;
  148. if (v == value || (value != null && value.equals(v)))
  149. return true;
  150. }
  151. return false;
  152. }
  153.  
  154. public V get(Object key) {
  155. Node<K, V> e;
  156. if ((e = getNode(hash(key), key)) == null)// hashMap方法
  157. return null;
  158. if (accessOrder)
  159. afterNodeAccess(e);// 把e节点移到最后。
  160. return e.value;
  161. }
  162.  
  163. public V getOrDefault(Object key, V defaultValue) {
  164. Node<K, V> e;
  165. if ((e = getNode(hash(key), key)) == null)// hashMap方法
  166. return defaultValue;
  167. if (accessOrder)// 把e节点移到最后。
  168. afterNodeAccess(e);
  169. return e.value;
  170. }
  171.  
  172. public void clear() {
  173. super.clear();
  174. head = tail = null;
  175. }
  176.  
  177. // 添加一个元素时候是否删除最老的。 map是缓存有用。比如到达100之后,添加一个元素就删除最老的元素。要重写。
  178. protected boolean removeEldestEntry(Map1.Entry<K, V> eldest) {
  179. return false;
  180. }
  181.  
  182. public Set<K> keySet() {
  183. Set<K> ks = keySet;
  184. if (ks == null) {
  185. ks = new LinkedKeySet();
  186. keySet = ks;
  187. }
  188. return ks;
  189. }
  190.  
  191. final class LinkedKeySet extends AbstractSet<K> {
  192. public final int size() {
  193. return size;
  194. }
  195.  
  196. public final void clear() {
  197. LinkedHashMap1.this.clear();
  198. }
  199.  
  200. public final Iterator<K> iterator() {
  201. return new LinkedKeyIterator();
  202. }
  203.  
  204. public final boolean contains(Object o) {
  205. return containsKey(o);
  206. }
  207.  
  208. public final boolean remove(Object key) {
  209. return removeNode(hash(key), key, null, false, true) != null;// hashMap方法
  210. }
  211.  
  212. public final Spliterator<K> spliterator() {
  213. return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
  214. }
  215.  
  216. public final void forEach(Consumer<? super K> action) {
  217. if (action == null)
  218. throw new NullPointerException();
  219. int mc = modCount;
  220. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
  221. action.accept(e.key);
  222. if (modCount != mc)
  223. throw new ConcurrentModificationException();
  224. }
  225. }
  226.  
  227. public Collection<V> values() {
  228. Collection<V> vs = values;
  229. if (vs == null) {
  230. vs = new LinkedValues();
  231. values = vs;
  232. }
  233. return vs;
  234. }
  235.  
  236. final class LinkedValues extends AbstractCollection<V> {
  237. public final int size() {
  238. return size;
  239. }
  240.  
  241. public final void clear() {
  242. LinkedHashMap1.this.clear();
  243. }
  244.  
  245. public final Iterator<V> iterator() {
  246. return new LinkedValueIterator();
  247. }
  248.  
  249. public final boolean contains(Object o) {
  250. return containsValue(o);
  251. }
  252.  
  253. public final Spliterator<V> spliterator() {
  254. return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED);
  255. }
  256.  
  257. public final void forEach(Consumer<? super V> action) {
  258. if (action == null)
  259. throw new NullPointerException();
  260. int mc = modCount;
  261. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
  262. action.accept(e.value);
  263. if (modCount != mc)
  264. throw new ConcurrentModificationException();
  265. }
  266. }
  267.  
  268. public Set<Map1.Entry<K, V>> entrySet() {
  269. Set<Map1.Entry<K, V>> es;
  270. return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
  271. }
  272.  
  273. final class LinkedEntrySet extends AbstractSet<Map1.Entry<K, V>> {
  274. public final int size() {
  275. return size;
  276. }
  277.  
  278. public final void clear() {
  279. LinkedHashMap1.this.clear();
  280. }
  281.  
  282. public final Iterator<Map1.Entry<K, V>> iterator() {
  283. return new LinkedEntryIterator();
  284. }
  285.  
  286. public final boolean contains(Object o) {
  287. if (!(o instanceof Map1.Entry))
  288. return false;
  289. Map1.Entry<?, ?> e = (Map1.Entry<?, ?>) o;
  290. Object key = e.getKey();
  291. Node<K, V> candidate = getNode(hash(key), key);// hashMap方法
  292. return candidate != null && candidate.equals(e);
  293. }
  294.  
  295. public final boolean remove(Object o) {
  296. if (o instanceof Map1.Entry) {
  297. Map1.Entry<?, ?> e = (Map1.Entry<?, ?>) o;
  298. Object key = e.getKey();
  299. Object value = e.getValue();
  300. return removeNode(hash(key), key, value, true, true) != null;// hashMap方法
  301. }
  302. return false;
  303. }
  304.  
  305. public final Spliterator<Map1.Entry<K, V>> spliterator() {
  306. return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
  307. }
  308.  
  309. public final void forEach(Consumer<? super Map1.Entry<K, V>> action) {
  310. if (action == null)
  311. throw new NullPointerException();
  312. int mc = modCount;
  313. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
  314. action.accept(e);
  315. if (modCount != mc)
  316. throw new ConcurrentModificationException();
  317. }
  318. }
  319.  
  320. public void forEach(BiConsumer<? super K, ? super V> action) {
  321. if (action == null)
  322. throw new NullPointerException();
  323. int mc = modCount;
  324. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
  325. action.accept(e.key, e.value);
  326. if (modCount != mc)
  327. throw new ConcurrentModificationException();
  328. }
  329.  
  330. public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
  331. if (function == null)
  332. throw new NullPointerException();
  333. int mc = modCount;
  334. for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
  335. e.value = function.apply(e.key, e.value);
  336. if (modCount != mc)
  337. throw new ConcurrentModificationException();
  338. }
  339.  
  340. public static class Entry<K, V> extends HashMap1.Node<K, V> {
  341. public Entry<K, V> before, after;// hash, key, value, next
  342.  
  343. public Entry(int hash, K key, V value, Node<K, V> next) {
  344. super(hash, key, value, next);// before和after引用节点以支持双向链表
  345. }
  346. }
  347.  
  348. abstract class LinkedHashIterator {//头结点head开始一路after到末尾
  349. LinkedHashMap1.Entry<K, V> next;
  350. LinkedHashMap1.Entry<K, V> current;
  351. int expectedModCount;
  352.  
  353. LinkedHashIterator() {
  354. next = head;// 初始化时下一个是head
  355. expectedModCount = modCount;
  356. current = null;
  357. }
  358.  
  359. public final boolean hasNext() {
  360. return next != null;
  361. }
  362.  
  363. final LinkedHashMap1.Entry<K, V> nextNode() {
  364. LinkedHashMap1.Entry<K, V> e = next;
  365. if (modCount != expectedModCount)
  366. throw new ConcurrentModificationException();
  367. if (e == null)
  368. throw new NoSuchElementException();
  369. current = e;
  370. next = e.after;// before和after遍历链表
  371. return e;
  372. }
  373.  
  374. public final void remove() {
  375. Node<K, V> p = current;
  376. if (p == null)
  377. throw new IllegalStateException();
  378. if (modCount != expectedModCount)
  379. throw new ConcurrentModificationException();
  380. current = null;
  381. K key = p.key;
  382. removeNode(hash(key), key, null, false, false);// hashMap方法
  383. expectedModCount = modCount;
  384. }
  385. }
  386.  
  387. final class LinkedKeyIterator extends LinkedHashIterator implements Iterator<K> {
  388. public final K next() {
  389. return nextNode().getKey();
  390. }
  391. }
  392.  
  393. final class LinkedValueIterator extends LinkedHashIterator implements Iterator<V> {
  394. public final V next() {
  395. return nextNode().value;
  396. }
  397. }
  398.  
  399. final class LinkedEntryIterator extends LinkedHashIterator implements Iterator<Map1.Entry<K, V>> {
  400. public final Map1.Entry<K, V> next() {
  401. return nextNode();
  402. }
  403. }
  404.  
  405. }

LinkedHashMap源码的更多相关文章

  1. 转:【Java集合源码剖析】LinkedHashmap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/37867985   前言:有网友建议分析下LinkedHashMap的源码,于是花了一晚上时 ...

  2. Java集合系列[4]----LinkedHashMap源码分析

    这篇文章我们开始分析LinkedHashMap的源码,LinkedHashMap继承了HashMap,也就是说LinkedHashMap是在HashMap的基础上扩展而来的,因此在看LinkedHas ...

  3. linkedHashMap源码解析(JDK1.8)

    引言 关于java中的不常见模块,让我一下子想我也想不出来,所以我希望以后每次遇到的时候我就加一篇.上次有人建议我写全所有常用的Map,所以我研究了一晚上LinkedHashMap,把自己感悟到的解释 ...

  4. LRU算法实现,HashMap与LinkedHashMap源码的部分总结

    关于HashMap与LinkedHashMap源码的一些总结 JDK1.8之后的HashMap底层结构中,在数组(Node<K,V> table)长度大于64的时候且链表(依然是Node) ...

  5. LinkedHashMap源码详解

    序言 本来是不打算先讲map的,但是随着对set集合的认识,发现如果不先搞懂各种map,是无法理解set的.因为set集合很多的底层就是用map来存储的.比如HashSet就是用HashMap,Lin ...

  6. 给jdk写注释系列之jdk1.6容器(5)-LinkedHashMap源码解析

    前面分析了HashMap的实现,我们知道其底层数据存储是一个hash表(数组+单向链表).接下来我们看一下另一个LinkedHashMap,它是HashMap的一个子类,他在HashMap的基础上维持 ...

  7. LinkedHashMap 源码详细分析(JDK1.8)

    1. 概述 LinkedHashMap 继承自 HashMap,在 HashMap 基础上,通过维护一条双向链表,解决了 HashMap 不能随时保持遍历顺序和插入顺序一致的问题.除此之外,Linke ...

  8. LinkedHashMap源码分析

    hashMap源码分析:hashMap源码分析 版本说明:jdk1.7LinkedHashMap继承于HashMap,是一个有序的Map接口的实现.有序指的是元素可以按照一定的顺序排列,比如元素的插入 ...

  9. LinkedHashMap源码分析及实现LRU

    概述 从名字上看LinkedHashMap相比于HashMap,显然多了链表的实现.从功能上看,LinkedHashMap有序,HashMap无序.这里的顺序指的是添加顺序或者访问顺序. 基本使用 @ ...

  10. 死磕 java集合之LinkedHashMap源码分析

    欢迎关注我的公众号"彤哥读源码",查看更多源码系列文章, 与彤哥一起畅游源码的海洋. 简介 LinkedHashMap内部维护了一个双向链表,能保证元素按插入的顺序访问,也能以访问 ...

随机推荐

  1. ubuntu与centos系统对比

    CentOS与Ubuntu该如何选择,哪个更好用.笔者在自媒体平台收集了一些网友的观点,较为经典,分享给大家.至于应该选择哪个,希望看完本文章后,读者心中有数. 观点1:CentOS适用于服务器,Ub ...

  2. spring AOP的两种配置

    xml配置 定义要被代理的方法的接口 public interface TestAop { public void print(String s); } 实现上述接口 public class Tes ...

  3. ./configure & make & make install 知其所以然

    最近一直在类unix系统上(Ubuntu和Mac OS)上调研第三方的一些开源库,要涉及到开源库的编译安装工作,接触最多的就是./configure & make & make ins ...

  4. Jpa的简介

    Jpa:是用于数据持久化的一组标准接口. 1.HelloWorld的编写 创建EntityManagerFactory 创建EntityManager 开启事务 数据持久化 提交事务 关闭Entity ...

  5. Spark GraphX图计算核心源码分析【图构建器、顶点、边】

    一.图构建器 GraphX提供了几种从RDD或磁盘上的顶点和边的集合构建图形的方法.默认情况下,没有图构建器会重新划分图的边:相反,边保留在默认分区中.Graph.groupEdges要求对图进行重新 ...

  6. java 使用网建SMS发送短信验证码

    首先, 注册并登录网建用户, 新注册用户将获得5条的测试短信 网建短信通地址: http://sms.webchinese.cn/default.shtml 注册账号在此就不多做赘述了, 直接上代码 ...

  7. 安装docker后,导致qemu的桥接网络出现问题

    按照Qemu-4.1 桥接网络设置中介绍的方法建立起桥接网络后,可以实现虚拟机和host的相互ping,但是在虚拟机里去ping其他跟host处于同一个网段的ip地址时却失败了,然后ifconfig后 ...

  8. 设置linux代理完成apt-get

    最近ubuntu的服务器被公司关闭了外网使用权限,但是安装软件又需要连接外网,那么就只能通过代理来连接了. 先按照下面的这篇帖子来设置windows端的代理. https://blog.csdn.ne ...

  9. scikit-learn 中的 KMeans

    语法 sklearn.cluster.KMeans(n_clusters=8, # 簇的个数, 默认为 8 init='k-means++', # 初始簇中心的获取方法 n_init=10, # 初始 ...

  10. MySQL体系结构与存储引擎

    MySQL 体系结构 先看 MySQL 数据库的体系结构,如下图所示. MySQL 体系结构由 Client Connectors 层.MySQL Server 层及存储引擎层组成. Client C ...