LinkedHashMap源码解析

LinkedHashMap继承了HashMap 实现了 Map,具有可预知的遍历顺序(按照插入顺序遍历,按照查询顺序遍历)。

LinkedHashMap和HashMap最大的不同是,在LinkedHushMap所有的entries里都会维护一个双向链表。

LinkedHashMap可用于做缓存,其中afterNodeInsertion可以在插入新节点之后调用,删除最早添加的结点(最少查询的结点),来保持map容量。

在LinkedHashMap定义了Entry类继承了HashMap.Nod,里面有一个构造方法,参数有:散列值、key、value和下一个元素的引用

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);
}
}

transient:head和tail不会被序列化

//最先被插入的元素
transient LinkedHashMap.Entry<K,V> head;
//最新被插入的元素
transient LinkedHashMap.Entry<K,V> tail;
//遍历顺序标志位,true:按照访问时顺序排序 false:按照插入时顺序排序
final boolean accessOrder;

构造函数:

/**** @param initialCapacity 初始容量* @param loadFactor 负载因子*/
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
//默认排序方式为按照插入顺序排序
accessOrder = false;
}
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
public LinkedHashMap() {
super();
accessOrder = false;
}

public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}

public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
//自己定义accessOrder
this.accessOrder = accessOrder;
}

判断值在LinkedHashMap中是否已存在

/*** 如果值在LinkedHashMap中已存在,返回true,否则返回false*/
public boolean containsValue(Object value) {
//遍历LinkedHashMap
for (LinkedHashMap.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;
}

根据key获取值,如果取不到返回null

public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return null;
//如果按照访问顺序排序
if (accessOrder)
//将该结点放到队尾
afterNodeAccess(e);
return e.value;
}

根据key获取值,如果取不到返回defaultValue

public V getOrDefault(Object key, V defaultValue) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null)
return defaultValue;
if (accessOrder)
afterNodeAccess(e);
return e.value;
}

将元素放在尾部

void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
//如果accessOrder 为真(按照访问顺序排序) 并且最后一个元素不是e
if (accessOrder && (last = tail) != e) {

//将e的类型强转为LinkedHashMap.Entry,获取e的前一个节点和后一个结点
LinkedHashMap.Entry<K,V> p =
(LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
因为要将e放在队尾,所以e的尾指针指向空
p.after = null;
//e前面没有结点(e是第一个结点)
if (b == null)
//a是表头结点
head = a;
else
否则将e的前一个结点的尾指针指向a(也就是e的后一个结点)
b.after = a;
//e不是最后一个结点
if (a != null)
//将e的后后一个结点的头指针指向e的前一个节点
a.before = b;
else
//last置为e的前一个节点
last = b;
//last为null,只有e一个结点
if (last == null)
//head为e
head = p;
else {
//e的头指针指向last
p.before = last;
//last的尾指针指向p
last.after = p;
}
//tail指向p
tail = p;
//记录HashMap被修改的次数
++modCount;
}
}

清空链表

public void clear() {
super.clear();
head = tail = null;
}

将结点放在尾部

private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
//last指向最新插入的结点
LinkedHashMap.Entry<K,V> last = tail;
//让tail指向p(tail指向最新插入节点)
tail = p;
//如果链表为空
if (last == null)
//p为头结点
head = p;
else {
p.before = last;
last.after = p;
}
}

将dst放在src原来的位置

private void transferLinks(LinkedHashMap.Entry<K,V> src,
LinkedHashMap.Entry<K,V> dst) {
LinkedHashMap.Entry<K,V> b = dst.before = src.before;
LinkedHashMap.Entry<K,V> a = dst.after = src.after;
原来src为头节点
if (b == null)
//头节点变为dst
head = dst;
else
//src前一个结点的尾指针指向dst
b.after = dst;
//src为为尾结点
if (a == null)
//tail指向dst
tail = dst;
else
src的后一个结点的头指针指向dst
a.before = dst;
}

重定义

void reinitialize() {super.reinitialize();head = tail = null;}

新建一个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;
}

替换结点

Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
LinkedHashMap.Entry<K,V> t =
new LinkedHashMap.Entry<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}

新建一个树节点

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);
return p;
}

替换树结点

TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMap.Entry<K,V> q = (LinkedHashMap.Entry<K,V>)p;
TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
transferLinks(q, t);
return t;
}

删除结点

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;
如果e为头节点
if (b == null)
将头节点引用指向e的后一个结点
head = a;
else
否则将e的前一个节点的尾指针指向a的后一个元素
b.after = a;
//如果e为尾结点
if (a == null)
//将e的前一个结点设为尾结点
tail = b;
else
//将e的后一个结点的头指针指向e的前一个节点
a.before = b;
}

插入新结点后调用(删除头节点,保持容量)

void afterNodeInsertion(boolean evict) { // possibly remove eldest
LinkedHashMap.Entry<K,V> first;
//如果evict不为空,头节点不为空,且removeEldestEntry返回为真(即在 removeEldestEntry未对map进行操作)
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
删除头节点
removeNode(hash(key), key, null, false, true);
}
}

重要:

  /**
         * 当有新的entry插入map中时,put和putAll将调用此方法,在每次插入新entry的时候可以删除eldest(即最早插入【最近最少被访问】),
         *如果map用于做缓存,这个方法会很有用·,它允许map删除过时的结点来减少内存的消耗
         *
         *一个简单的例子: 允许map最多有100个entry,每次有新entry插入时,都会删除eldest,让map保持持有稳定的100个entry。
         * private static final int MAX_ENTRIES = 100;
         *
         * protected boolean removeEldestEntry(Map.Entry eldest) {
         * return size() &gt; MAX_ENTRIES;
         * }
         *
         *
         * 这个方法通常不会直接修改map,而是通过返回值,让map自行修改,
         *也可以通过这个方法直接修改map,如果这样做了,这个方法必须要返回false(表示map自身不需要再进行修改)。
         * @param eldest  最早插入结点或者在按照顺寻访问模式下,最近最少被查询过的结点。
         * @return true :如果entry被删除;false:如果entry被保留。
         */
        protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
            return false;
        }

仅从WriteObject调用,以确保顺序兼容

void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}

遍历map

public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
//函数式接口的一个方法
action.accept(e.key, e.value);
//为了避免多个迭代次同时操作对象
if (modCount != mc)
throw new ConcurrentModificationException();
}

将所有结点值和key换为function

public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
if (function == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
e.value = function.apply(e.key, e.value);
if (modCount != mc)
throw new ConcurrentModificationException();
}

返回LinkedKeySet

/*** 返回mao中包含的key set.*/
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new LinkedKeySet();
keySet = ks;
}
return ks;
}

LinkedEntrySet 类

final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new LinkedEntryIterator();
}
/**
*是否包含这个entry
*/
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}

/**
*删除entry
*/
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
/**
*截取
*/
public final Spliterator<Map.Entry<K,V>> spliterator() {
return Spliterators.spliterator(this, Spliterator.SIZED |
Spliterator.ORDERED |
Spliterator.DISTINCT);
}
/**
*遍历
*/
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
//函数式接口的一个方法
action.accept(e);
if (modCount != mc)
throw new ConcurrentModificationException();
}
}

LinkedEntryIterator结点迭代器

final class LinkedEntryIterator extends LinkedHashIterator
//实现了迭代器
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}

LinkedHashIterator

abstract class LinkedHashIterator {
LinkedHashMap.Entry<K,V> next;
LinkedHashMap.Entry<K,V> current;
int expectedModCount;

LinkedHashIterator() {
next = head;
//迭代器对map修改的次数
expectedModCount = modCount;
current = null;
}

/**
*是否还有下一个节点
*/
public final boolean hasNext() {
return next != null;
}

/**
*获取下一个node
*/
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;
}
}

LinkedKeyIterator key迭代器

final class LinkedKeyIterator extends LinkedHashIterator
implements Iterator<K> {
public final K next() { return nextNode().getKey(); }
}

LinkedValueIterator 值迭代器

final class LinkedValueIterator extends LinkedHashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值