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把所有元素串联起来了。

public class testLinkedHashMap1 {
@SuppressWarnings({ "rawtypes", "unchecked" })
public static void main(String[] args) {
LinkedHashMap1<Integer,String> hh = new LinkedHashMap1<Integer,String>(); //链表添加
hh.put(, "");//放到LinkedHashMap1的table[0]中,此时是链表(节点有next没有after,before)
hh.put(, "");
// hh.remove(4);//链表删除
// hh.put(4, "4");
hh.put(, "");
hh.put(, "");//0位置转成红黑树
hh.put(, "");
hh.put(, "");
hh.put(, "");
hh.put(, "");//1位置链表添加
hh.put(, "");
hh.put(, ""); hh.get(); Set s = hh.keySet();//[0, 16, 32, 48, 54, 60, 76, 1, 2, 3]
Iterator i = s.iterator();
if(i.hasNext()) System.out.println(i.next());
// i.remove();
if(i.hasNext()) System.out.println(i.next()); }
}
//extends HashMap1,table也被继承过来,数组+链表+红黑树。
public class LinkedHashMap1<K, V> extends HashMap1<K, V> implements Map1<K, V> {
private static final long serialVersionUID = 3801124242820219131L;
transient LinkedHashMap1.Entry<K, V> head;// 双向链表的头节点和尾节点
transient LinkedHashMap1.Entry<K, V> tail;
final boolean accessOrder;// true,使用节点之后就把节点放到最末尾。false就不放。用于删除第一个最不常用的元素。 private void linkNodeLast(LinkedHashMap1.Entry<K, V> p) {// 链表末尾添加,有before,after
LinkedHashMap1.Entry<K, V> last = tail;//保留原来的tail
tail = p;//修改tail
if (last == null)// tail=null
head = p;// tail = head = p
else {
p.before = last;
last.after = p;
}
} // dst替换src
private void transferLinks(LinkedHashMap1.Entry<K, V> src, LinkedHashMap1.Entry<K, V> dst) {
LinkedHashMap1.Entry<K, V> b = dst.before = src.before;
LinkedHashMap1.Entry<K, V> a = dst.after = src.after;
if (b == null)// 替换的src是第一个节点
head = dst;
else
b.after = dst;
if (a == null)// 替换的src是最后一个节点
tail = dst;
else
a.before = dst;
} public void reinitialize() {
super.reinitialize();// table = null; entrySet = null; keySet = null; values = null;
head = tail = null;
}
//生成一个节点(链表中的节点,不是红黑树中的节点,有hash, key, value, next没有before,after)
public Node<K, V> newNode(int hash, K key, V value, Node<K, V> e) {//
LinkedHashMap1.Entry<K, V> p = new LinkedHashMap1.Entry<K, V>(hash, key, value, e);
linkNodeLast(p);// 生成新的节点并插入到尾部
return p;
} public Node<K, V> replacementNode(Node<K, V> p, Node<K, V> next) {
LinkedHashMap1.Entry<K, V> q = (LinkedHashMap1.Entry<K, V>) p;
LinkedHashMap1.Entry<K, V> t = new LinkedHashMap1.Entry<K, V>(q.hash, q.key, q.value, next);
transferLinks(q, t);// t替换q
return t;
} public TreeNode<K, V> newTreeNode(int hash, K key, V value, Node<K, V> next) {
TreeNode<K, V> p = new TreeNode<K, V>(hash, key, value, next);
linkNodeLast(p);// 末尾添加p
return p;
} public TreeNode<K, V> replacementTreeNode(Node<K, V> p, Node<K, V> next) {
LinkedHashMap1.Entry<K, V> q = (LinkedHashMap1.Entry<K, V>) p;
TreeNode<K, V> t = new TreeNode<K, V>(q.hash, q.key, q.value, next);
transferLinks(q, t);// t替换q
return t;
} public void afterNodeRemoval(Node<K, V> e) { // 删除节点e
LinkedHashMap1.Entry<K, V> p = (LinkedHashMap1.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;
} public void afterNodeInsertion(boolean evict) { // 添加新的节点时候,有可能删除最老的元素
LinkedHashMap1.Entry<K, V> first;
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;// 删除第一个元素,每次使用元素之后,就会把元素放到最末尾,第一个元素就是最少使用的元素。
removeNode(hash(key), key, null, false, true);// hashMap方法,
}
} public void afterNodeAccess(Node<K, V> e) { // 节点e被修改后,e不是尾节点(e是尾节点就不动),把e节点移到最后。
LinkedHashMap1.Entry<K, V> last;
if (accessOrder && (last = tail) != e) {
LinkedHashMap1.Entry<K, V> p = (LinkedHashMap1.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;
}
} public void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after) {
s.writeObject(e.key);
s.writeObject(e.value);
}
} public LinkedHashMap1(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
accessOrder = false;// true,使用节点之后就把节点放到最末尾。false就不放。
} public LinkedHashMap1(int initialCapacity) {
super(initialCapacity);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
accessOrder = false;
} public LinkedHashMap1() {
super();// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
accessOrder = false;
} public LinkedHashMap1(Map1<? extends K, ? extends V> m) {
super();// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
accessOrder = false;
putMapEntries(m, false);
} public LinkedHashMap1(int initialCapacity, float loadFactor, boolean accessOrder) {
super(initialCapacity, loadFactor);// hashMap方法,构造hashMap的table,一个数组+链表+红黑树
this.accessOrder = accessOrder;
} public boolean containsValue(Object value) {
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after) {
V v = e.value;
if (v == value || (value != null && value.equals(v)))
return true;
}
return false;
} public V get(Object key) {
Node<K, V> e;
if ((e = getNode(hash(key), key)) == null)// hashMap方法
return null;
if (accessOrder)
afterNodeAccess(e);// 把e节点移到最后。
return e.value;
} public V getOrDefault(Object key, V defaultValue) {
Node<K, V> e;
if ((e = getNode(hash(key), key)) == null)// hashMap方法
return defaultValue;
if (accessOrder)// 把e节点移到最后。
afterNodeAccess(e);
return e.value;
} public void clear() {
super.clear();
head = tail = null;
} // 添加一个元素时候是否删除最老的。 map是缓存有用。比如到达100之后,添加一个元素就删除最老的元素。要重写。
protected boolean removeEldestEntry(Map1.Entry<K, V> eldest) {
return false;
} public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new LinkedKeySet();
keySet = ks;
}
return ks;
} final class LinkedKeySet extends AbstractSet<K> {
public final int size() {
return size;
} public final void clear() {
LinkedHashMap1.this.clear();
} public final Iterator<K> iterator() {
return new LinkedKeyIterator();
} public final boolean contains(Object o) {
return containsKey(o);
} public final boolean remove(Object key) {
return removeNode(hash(key), key, null, false, true) != null;// hashMap方法
} public final Spliterator<K> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
} public final void forEach(Consumer<? super K> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
action.accept(e.key);
if (modCount != mc)
throw new ConcurrentModificationException();
}
} public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new LinkedValues();
values = vs;
}
return vs;
} final class LinkedValues extends AbstractCollection<V> {
public final int size() {
return size;
} public final void clear() {
LinkedHashMap1.this.clear();
} public final Iterator<V> iterator() {
return new LinkedValueIterator();
} public final boolean contains(Object o) {
return containsValue(o);
} public final Spliterator<V> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED);
} public final void forEach(Consumer<? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
action.accept(e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
}
} public Set<Map1.Entry<K, V>> entrySet() {
Set<Map1.Entry<K, V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
} final class LinkedEntrySet extends AbstractSet<Map1.Entry<K, V>> {
public final int size() {
return size;
} public final void clear() {
LinkedHashMap1.this.clear();
} public final Iterator<Map1.Entry<K, V>> iterator() {
return new LinkedEntryIterator();
} public final boolean contains(Object o) {
if (!(o instanceof Map1.Entry))
return false;
Map1.Entry<?, ?> e = (Map1.Entry<?, ?>) o;
Object key = e.getKey();
Node<K, V> candidate = getNode(hash(key), key);// hashMap方法
return candidate != null && candidate.equals(e);
} public final boolean remove(Object o) {
if (o instanceof Map1.Entry) {
Map1.Entry<?, ?> e = (Map1.Entry<?, ?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;// hashMap方法
}
return false;
} public final Spliterator<Map1.Entry<K, V>> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
} public final void forEach(Consumer<? super Map1.Entry<K, V>> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
action.accept(e);
if (modCount != mc)
throw new ConcurrentModificationException();
}
} public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
action.accept(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
} public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
if (function == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap1.Entry<K, V> e = head; e != null; e = e.after)
e.value = function.apply(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
} public static class Entry<K, V> extends HashMap1.Node<K, V> {
public Entry<K, V> before, after;// hash, key, value, next public Entry(int hash, K key, V value, Node<K, V> next) {
super(hash, key, value, next);// before和after引用节点以支持双向链表
}
} abstract class LinkedHashIterator {//头结点head开始一路after到末尾
LinkedHashMap1.Entry<K, V> next;
LinkedHashMap1.Entry<K, V> current;
int expectedModCount; LinkedHashIterator() {
next = head;// 初始化时下一个是head
expectedModCount = modCount;
current = null;
} public final boolean hasNext() {
return next != null;
} final LinkedHashMap1.Entry<K, V> nextNode() {
LinkedHashMap1.Entry<K, V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
current = e;
next = e.after;// before和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);// hashMap方法
expectedModCount = modCount;
}
} 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<Map1.Entry<K, V>> {
public final Map1.Entry<K, V> next() {
return nextNode();
}
} }

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. Python基础14

    P73. 内嵌函数的讲解介绍 内部函数,书中讲的应用较简单,后面找篇具体的文章学习下

  2. nginx 反向代理时丢失端口的解决方案(转)

    今天,配置nginx反向代理时遇到一个问题,当设置nginx监听80端口时转发请求没有问题.但一旦设置为监听其他端口,就一直跳转不正常:如,访问欢迎页面时应该是重定向到登录页面,在这个重定向的过程中端 ...

  3. i春秋——“百度杯”CTF比赛 九月场——Test(海洋cms / seacms 任意代码执行漏洞)

    打开发现是海洋cms,那就搜索相关漏洞 找到一篇介绍海洋cms的命令执行漏洞的文章:https://www.jianshu.com/p/ebf156afda49 直接利用其中给出的poc /searc ...

  4. CTF-代码审计(2)

    1.bugku 备份是个好习惯 网址:http://123.206.87.240:8002/web16/ 进去什么都没有,题目说备份想到备份文件,所以直接再后面加个    .bak 拿到源码: < ...

  5. loadrunner总结

    loadrunner总结 1.性能测试包含了哪些测试(至少举出3种) 负载测试,压力测试,疲劳强度测试,大数据量测试,并发测试. 2.负载测试和压力测试的区别 性能测试: 是通过自动化的测试工具模拟多 ...

  6. CDH报错:PersistenceException: [PersistenceUnit: cmf.server] Unable to build EntityManagerFactory

    1.在启动CDH中master的服务cloudera-scm-server start并立刻挂掉了,提示如下错误 org.springframework.beans.factory.BeanCreat ...

  7. day 45

    目录 form表单(**************) 参数 action method select标签 下拉框 textarea标签 CSS 注释 css的语法结构 css的三种引入方式 css查找( ...

  8. 利用 FluentScheduler 启动定时器计划任务

    FluentScheduler 是什么? Automated job scheduler with fluent interface. 这是作者在 Github 上的介绍,就是一个定时任务管理器.在 ...

  9. SpringBoot——配置文件详解【五】

    前言 SpringBoot的配置文件 配置文件 SpringBoot使用一个全局的配置文件,配置文件名是固定的. application.properties application.yml 配置文件 ...

  10. 平台级 SAAS 架构的基础:统一身份管理系统

    https://my.oschina.net/bochs/blog/2248954 业内在用户统一身份认证及授权管理领域,主要关注 4 个方面:集中账号管理(Account).集中认证管理(Authe ...