LinkedHashMap 实现原理

LinkedHashMap结合了哈希表和链表的特性,保证了迭代时的插入顺序。它通过重写HashMap的访问、插入和删除方法来维护链表的有序性。在访问节点不是尾节点时,会将其移动到链表尾部。get方法直接调用HashMap的getNode方法,put和remove方法未重写。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

LinkedHashMap 是通过哈希表和链表实现的,它通过维护一个链表来保证对哈希表迭代时的有序性,而这个有序是指键值对插入的顺序。另外,当向哈希表中重复插入某个键的时候,不会影响到原来的有序性。也就是说,假设你插入的键的顺序为 1、 2、 3、 4,后来再次插入 2,迭代时的顺序还是 1、 2、3、 4,而不会因为后来插入的 2 变成 1、 3、 4、 2。(但可以改变它的规则,使它变成 1、 3、 4、 2)
LinkedHashMap 的实现主要分两部分,一部分是哈希表,另外一部分是链表。哈希表部分继承了HashMap,链表部分维护有序性。
LinkedHashMap 大致实现

  1. 声明
//继承了HashMap 实现了map接口
public class LinkedHashMap<K,V> extends HashMap<K,V> 
   								implements Map<K,V>
  1. 属性
    与链表相关的属性

链表节点

//LinkedHashMap 的链表节点继承了 HashMap 的节点,而且每个节点都包含了前指针和后指针,所以这里可以看出它是一个双向链表
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 LinkedHashMap.Entry<K,V> head;

//尾指针
transient LinkedHashMap.Entry<K,V> tail;

//默认为 false。当为 true 时,表示链表中键值对的顺序与每个键的插入顺序一致,也就是说重复插入键,也会更新顺序
//简单来说,为 false 时,就是上面所指的 1、 2、 3、 4 的情况;为 true 时,就是 1、 3、 4、 2 的情况
final boolean accessOrder;

3.方法

HashMap中有三个空方法,表示的是在访问、插入、删除某个节点之后,进行一些处理,在LinkedHashMap中有各自的实现,LinkedHashMap通过重写这三个方法来保证链表的插入、删除的有序性

// Callbacks to allow LinkedHashMap post-actions
void afterNodeAccess(Node<K,V> p) { }
void afterNodeInsertion(boolean evict) { }
void afterNodeRemoval(Node<K,V> p) { }
  1. afterNodeAccess 方法
    核心:判断访问节点是否为链表的尾节点,是尾节点时不需要进行任何操作,否则将节点移至链表尾部
void afterNodeAccess(Node<K,V> e) { // move node to last
   	LinkedHashMap.Entry<K,V> last;
   	//当 accessOrder 的值为 true,(代表根据插入顺序进行更新),且 e 不是尾节点
   	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.after = b;
   		else 
   			last = b;
   		if (last == null) 
   			head = p;
   		else
   			p.befter = last;
   			last.after = p;
   		tail = p;
   		++ modCount;
   	}
}
  1. afterNodeInsertion方法
    插入一个新节点时进行调用,会把链表的头节点删除,删除方式使用HashMap的removeNode方法
    当在尾部插入新节点,以及访问某节点将其放置链表尾部,头节点最少访问被删除
    其中需重写removeEldestEntry方法
void afterNodeInsertion(boolean evict) { // possibly remove eldest
   LinkedHashMap.Entry<K,V> first;
   if (evict && (first = head) != null && removeEldestEntry(first)) {
   		K key = first.key;
   		removeNode(hash(key), key, null, false, true);
   }
}

  1. 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;
}

4.get方法
调用 HashMap 的getNode 方法来获取结果。

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

put方法和remove方法没有进行重写

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值