JDK 1.8 LinkdhashMapソース分析
97061 ワード
ソースはそんなに長くないので、直接貼り付けます.は、Linked HashMapがHashMapから継承されているのを見られます.一方、mapインターフェースの最新のJDK 1.8 hashMapのデータ構造は、配列+チェーン+レッドツリーです. Linked HashMapはHashMapのデータ構造に基づいて、双方向チェーン を追加しました. hashMapは無秩序であり、Linked HashMapはこの欠点を補っています.デフォルトは挿入順序で、つまり最後に挿入されたkey-valueは双方向チェーンの末尾に追加されます.accessOrderがtrueであると定義されると、アクセス順であるputkey-valueの後に、getを呼び出して、replacacacacacaccessなどの方法は、ノードをリンクの末尾に配置します.よく使うデータはチェーンの最後にあります. ここでは、RemoveEldest Enterryインターフェースを実現することによって、自分のLRUアルゴリズム、すなわちput key-valueをカスタマイズした後、自分の業務のLRU需要に応じて、最も古いデータノード(すなわち、双方向リンクノードの先頭ノード)を削除することができます.
package java.util;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.io.IOException;
public class LinkedHashMap<K,V>
extends HashMap<K,V>
implements Map<K,V>
{
//LinkedHashMap ,
static class LinkedHashMapEntry<K,V> extends HashMap.Node<K,V> {
// HashMap.Node before,after
LinkedHashMapEntry<K,V> before, after;
LinkedHashMapEntry(int hash, K key, V value, Node<K,V> next) {
super(hash, key, value, next);
}
}
private static final long serialVersionUID = 3801124242820219131L;
//
transient LinkedHashMapEntry<K,V> head;
//
transient LinkedHashMapEntry<K,V> tail;
// ( entrySet):
//accessOrder=true
//access-order=false
final boolean accessOrder;
// p
private void linkNodeLast(LinkedHashMapEntry<K,V> p) {
LinkedHashMapEntry<K,V> last = tail; //
tail = p; //
// null
// null
// p
if (last == null)
head = p;
// null
else {
//
p.before = last;
last.after = p;
}
}
// dst src
private void transferLinks(LinkedHashMapEntry<K,V> src,
LinkedHashMapEntry<K,V> dst) {
LinkedHashMapEntry<K,V> b = dst.before = src.before;
LinkedHashMapEntry<K,V> a = dst.after = src.after;
// dst null
if (b == null)
// dst
head = dst;
// dst null
else
// dst dst
b.after = dst;
// dst null
if (a == null)
// dst
tail = dst;
// dst null
else
// dst dst
a.before = dst;
}
// 。 clone readObject
void reinitialize() {
super.reinitialize();
head = tail = null;
}
// HashMap
//
Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
//
LinkedHashMapEntry<K,V> p =
new LinkedHashMapEntry<K,V>(hash, key, value, e);
//
linkNodeLast(p);
return p;
}
// HashMap
Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {
LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
//
LinkedHashMapEntry<K,V> t =
new LinkedHashMapEntry<K,V>(q.hash, q.key, q.value, next);
// ,
transferLinks(q, t);
return t;
}
// HashMap
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);
//
// TreeNode LinkedHashMapEntry
// HashMap :
//TreeNode extends LinkedHashMap.LinkedHashMapEntry
linkNodeLast(p);
return p;
}
// HashMap
TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {
// newNode , LinkedHashMapEntry
LinkedHashMapEntry<K,V> q = (LinkedHashMapEntry<K,V>)p;
TreeNode<K,V> t = new TreeNode<K,V>(q.hash, q.key, q.value, next);
// ,
// TreeNode LinkedHashMapEntry
// HashMap :
//TreeNode extends LinkedHashMap.LinkedHashMapEntry
transferLinks(q, t);
return t;
}
// HashMap LinkedHashMap
//HashMap
void afterNodeRemoval(Node<K,V> e) {
// p = e
// b = p
// a = p
LinkedHashMapEntry<K,V> p = (LinkedHashMapEntry<K,V>)e,
b = p.before, a = p.after;
// p , null
p.before = p.after = null;
// b null,
if (b == null)
// p
head = a;
// b null,
else
// b a
b.after = a;
// a null,
if (a == null)
// p
tail = b;
// a null,
else
// a b
a.before = b;
}
//HashMap
//evict = false ,
void afterNodeInsertion(boolean evict) { // possibly remove eldest
//
LinkedHashMapEntry<K,V> first;
// null removeEldestEntry true
//
if (evict && (first = head) != null && removeEldestEntry(first)) {
K key = first.key;
removeNode(hash(key), key, null, false, true);
}
}
//HashMap put、replace
// LinkedHashMap put,replace,get ,
//
void afterNodeAccess(Node<K,V> e) {
// last
LinkedHashMapEntry<K,V> last;
// accessOrder true e
if (accessOrder && (last = tail) != e) {
// p = e
// b = p
// a = p
LinkedHashMapEntry<K,V> p =(LinkedHashMapEntry<K,V>)e,
b = p.before, a = p.after;
// p , p null
p.after = null;
// b null , p
if (b == null)
// p
head = a;
else
// b a
b.after = a;
// a null,
if (a != null)
// a b
a.before = b;
else
// a null, p
// last b
last = b;
// null , null
if (last == null)
// p
head = p;
else {
// p last
p.before = last;
//last p
last.after = p;
}
// p, e
tail = p;
++modCount; // 1
}
}
//------------------------------------------------------------
//
void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {
for (LinkedHashMapEntry<K,V> e = head; e != null; e = e.after) {
s.writeObject(e.key);
s.writeObject(e.value);
}
}
//
//initialCapacity:
//loadFactor:
// accessOrder false
public LinkedHashMap(int initialCapacity, float loadFactor) {
super(initialCapacity, loadFactor);
accessOrder = false;
}
//
//initialCapacity:
// accessOrder false
public LinkedHashMap(int initialCapacity) {
super(initialCapacity);
accessOrder = false;
}
//
// accessOrder false
public LinkedHashMap() {
super();
accessOrder = false;
}
//
//m: map
// accessOrder false
public LinkedHashMap(Map<? extends K, ? extends V> m) {
super();
accessOrder = false;
putMapEntries(m, false);
}
//
//initialCapacity:
//loadFactor:
//accessOrder:
public LinkedHashMap(int initialCapacity,
float loadFactor,
boolean accessOrder) {
super(initialCapacity, loadFactor);
this.accessOrder = accessOrder;
}
// value
// , O(n)
public boolean containsValue(Object value) {
for (LinkedHashMapEntry<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;
}
// get
// HashMap getNode
//getNode null accessOrder true ,
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;
}
// getOrDefault
// HashMap getNode
//getNode null accessOrder true ,
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;
}
// ,
public void clear() {
super.clear();
head = tail = null;
}
// ,
public Map.Entry<K, V> eldest() {
return head;
}
//LinkedHashMap false
// , , LinkedHashMap,
// removeEldestEntry
protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
return false;
}
// key
public Set<K> keySet() {
Set<K> ks = keySet;
if (ks == null) {
ks = new LinkedKeySet();
keySet = ks;
}
return ks;
}
// KeySet
final class LinkedKeySet extends AbstractSet<K> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
// LinkedHashMap
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;
}
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 (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
action.accept(e.key);
// LinkedHashMap ( put, remove ),
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
//value
public Collection<V> values() {
Collection<V> vs = values;
if (vs == null) {
vs = new LinkedValues();
values = vs;
}
return vs;
}
// value
final class LinkedValues extends AbstractCollection<V> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
// LinkedHashMap
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 (LinkedHashMapEntry<K,V> e = head; (e != null && modCount == mc); e = e.after)
action.accept(e.value);
// LinkedHashMap ( put, remove ),
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
//
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new LinkedEntrySet()) : es;
}
//
final class LinkedEntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { LinkedHashMap.this.clear(); }
// LinkedHashMap
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 (LinkedHashMapEntry<K,V> e = head; (e != null && mc == modCount); e = e.after)
action.accept(e);
// LinkedHashMap ( put, remove ),
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
// Map overrides
public void forEach(BiConsumer<? super K, ? super V> action) {
if (action == null)
throw new NullPointerException();
int mc = modCount;
for (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
action.accept(e.key, e.value);
// LinkedHashMap ( put, remove ),
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 (LinkedHashMapEntry<K,V> e = head; modCount == mc && e != null; e = e.after)
e.value = function.apply(e.key, e.value);
// LinkedHashMap ( put, remove ),
if (modCount != mc)
throw new ConcurrentModificationException();
}
//
abstract class LinkedHashIterator {
// next
LinkedHashMapEntry<K,V> next;
//
LinkedHashMapEntry<K,V> current;
//
// ( put, remove )
// , expectedModCount != modCount,
int expectedModCount;
LinkedHashIterator() {
next = head; //
expectedModCount = modCount; //expectedModCount
current = null; // , null
}
//
public final boolean hasNext() {
return next != null;
}
//
final LinkedHashMapEntry<K,V> nextNode() {
//
LinkedHashMapEntry<K,V> e = next;
// LinkedHashMap ( put, remove )
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// null,
if (e == null)
throw new NoSuchElementException();
//
current = e;
//next
next = e.after;
return e;
}
//
public final void remove() {
//
Node<K,V> p = current;
if (p == null)
throw new IllegalStateException();
// LinkedHashMap ( put, remove )
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
// null
current = null;
//
K key = p.key;
removeNode(hash(key), key, null, false, false);
//
expectedModCount = modCount;
}
}
//key
final class LinkedKeyIterator extends LinkedHashIterator
implements Iterator<K> {
public final K next() { return nextNode().getKey(); }
}
//value
final class LinkedValueIterator extends LinkedHashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
//Entry
final class LinkedEntryIterator extends LinkedHashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
}