有序的
实体 Entry
源码
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);
}
}
说明
Entry<K,V> before, after;
reinitialize() 初始化散列表和双向链表
源码
void reinitialize() {
super.reinitialize();
head = tail = null;
}
newNode() 创建一个entry,将entry插入到双向链表的末尾,最后反回entry
源码
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了
,而是Entry节点5个构造
方法解析
LinkedHashMap(int intialCapacity, float loadFactor)
源码
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
注意点
accessOrder = false;
可以看出,LinkedHashMap是插入顺序的
测试
// 测试默认插入有序
Map<String, String> test = new LinkedHashMap<>();
for (int i = 0; i < 16; i++) {
test.put("CT-" + i, "Lee测试-ST" + i);
}
// 遍历
// 1、拿到key结合
Set<String> keys = test.keySet();
for (String key : keys) {
System.out.println("key: " + key + " -----------------> " + test.get(key));
}
key: CT-0 -----------------> Lee测试-ST0
key: CT-1 -----------------> Lee测试-ST1
key: CT-2 -----------------> Lee测试-ST2
key: CT-3 -----------------> Lee测试-ST3
key: CT-4 -----------------> Lee测试-ST4
key: CT-5 -----------------> Lee测试-ST5
key: CT-6 -----------------> Lee测试-ST6
key: CT-7 -----------------> Lee测试-ST7
key: CT-8 -----------------> Lee测试-ST8
key: CT-9 -----------------> Lee测试-ST9
key: CT-10 -----------------> Lee测试-ST10
key: CT-11 -----------------> Lee测试-ST11
key: CT-12 -----------------> Lee测试-ST12
key: CT-13 -----------------> Lee测试-ST13
key: CT-14 -----------------> Lee测试-ST14
key: CT-15 -----------------> Lee测试-ST15
创建节点时,调用的是LinkedHashMap的方法
源码
public V get(Object key) {
Node<K,V> e;
if ((e = getNode(hash(key), key)) == null) // 调用的HashMap的方法
return null;
if (accessOrder)
afterNodeAccess(e); // 把该节点放到链表的最后面
return e.value;
}
逻辑
直接调用的HashMap的get做的处理
如果 accessOrder 为true(访问顺序),那就调用afterNodeAccess
把节点移动到链表的最后
afterNodeAccess方法
源码
void afterNodeAccess(Node<K,V> e) { // move node to last
LinkedHashMap.Entry<K,V> last;
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.before = b;
else
last = b;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
tail = p;
++modCount;
}
}
remove本身没有重写,直接调用的hashMap的remove
但是重写了 afterNodeRemoval(Node<K,V> e) 方法
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;
}
重写了 EntrySet
源码
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
可以看出,LinkedHashMap的遍历是对内部维护的一个双向链表的遍历,从而推断出,初始化容量对遍历不是有影响的,但是双向链表的元素,都来源于散列表中
newNode
方法重写了,在以LinkedHashMap的对象调用put方法时,走到newNode函数的时候,会去调用HashMap子类的LinkedHashMap的重写的newNode方法 -> 多态的强大访问顺序
(access-ordered) 在调用get方法时,会改变链表的结构插入顺序
(insertion-ordered)(插入的时候,所有的节点都是有序的)访问顺序
用处不大
访问顺序(access-ordered)
为LRU算法实现提供服务的原文:https://www.cnblogs.com/JQ04/p/15096327.html