<> linkedhashmap如何保证有序
2019-06-03 本文已影响0人
monk87
LinkedHashMap
这个基础类,默认支持按照插入的书序去访问.这个是怎么做到的 ?
其实很简单 ,就是这个类内部维护了一个双向链表.有了这个双向链表,往前往后都很好控制顺序.
//看一个测试代码
LinkedHashMap<String, String> s = new LinkedHashMap<>();
//
s.put("a", "1");
s.put("b", "2");
s.put("c", "3");
//
Iterator<Map.Entry<String, String>> iterator = s.entrySet().iterator();
//输出了顺序 a,b,c
while (iterator.hasNext()) {
Map.Entry<String, String> next = iterator.next();
System.out.println("kv: " + next.getKey() + " : " + next.getValue());
}
这个是怎么实现的 ? 首先他继承
HashMap
, hashmap再put的时候,linkedhashmap重写了构建node部分
//新建一个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;
}
//构建自身的链表
// link at the end of list
private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
LinkedHashMap.Entry<K,V> last = tail;
tail = p;
if (last == null)
head = p;
else {
p.before = last;
last.after = p;
}
}
完成了这个 之后,在访问的时候就可以使用这个链表了 .请看下面分析
首先自己实现了 LinkedEntrySet
和 LinkedHashIterator
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();
}
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);
}
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();
}
}
final class LinkedEntryIterator extends LinkedHashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
可以看到调用的时候根据entryset拿到iterator之后 返回的是自己类的iteraotr,重写了
next()
函数,直接调用
nextNode()
. 请看下nextndoe
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;
}
可以看到 .其实就是再访问自己构建的这个链表