Heim >Java >javaLernprogramm >Detaillierte Erläuterung von HashMap in Java-Sammlungen
HashMap ist eine Hash-Tabelle und der gespeicherte Inhalt ist eine Schlüssel-Wert-Zuordnung. HashMap erbt von AbstractMap und implementiert die Schnittstellen Map, Cloneable und Serializable.
(1) HashMap ist nicht threadsicher und der Schlüsselwert kann null sein und ist ungeordnet.
(2) Die anfängliche Größe von HashMap beträgt 16, die maximale Größe beträgt 2 hoch 30 und der Standardladefaktor beträgt 0,75.
(3) Die anfängliche Kapazität ist lediglich die Kapazität der Hash-Tabelle bei ihrer Erstellung, und der Auslastungsfaktor ist ein Maß dafür, wie voll die Hash-Tabelle sein kann, bevor ihre Kapazität automatisch erhöht wird. Wenn die Anzahl der Einträge in der Hash-Tabelle das Produkt aus Auslastungsfaktor und aktueller Kapazität übersteigt, muss die Hash-Tabelle erneut aufbereitet werden (Neuaufbau der internen Datenstruktur)
Die Beziehung zwischen HashMap und Map ist wie folgt:
(1) HashMap erbt von der AbstractMap-Klasse und implementiert die Map-Schnittstelle.
(2) HashMap implementiert eine Hash-Tabelle über die Zipper-Methode. Mehrere wichtige Mitgliedsvariablen sind: Tabelle, Größe, Schwellenwert, LoadFactor, ModCount.
table ist ein Entry[]-Array-Typ. Entry ist eigentlich eine einseitig verknüpfte Liste. Die Schlüsselwerte von HashMap werden in diesem Array gespeichert.
Größe ist die Größe von HashMap, also die Anzahl der von HashMap gespeicherten Schlüssel-Wert-Paare.
Schwellenwert ist der Schwellenwert von HashMap, der verwendet wird, um zu bestimmen, ob die Kapazität von HashMap angepasst werden muss. Der Wert von Schwellenwert entspricht der Kapazität multipliziert mit dem Ladefaktor Schwellenwert muss die Kapazität der HashMap verdoppelt werden.
loadFactor Ladefaktor
modCount wird verwendet, um den Fail-Fast-Mechanismus zu implementieren.
HashMap-Traversal-Methode:
(1) Traversieren Sie die Schlüssel-Wert-Paare von HashMap: Der erste Schritt besteht darin, den Eintragssatz über enterSet( ) Funktion, Der zweite Schritt besteht darin, die Eintragssammlung durch den Iterator zu durchlaufen, um die Daten zu erhalten
Integer Iterator =map.entrySet().iterator()(iterator.hasNext()) { Map.Entry entry=(Map.Entry)iterator.next()key=(String)enrty.getKey()value=(Integer)entry.getValue()}
(2) Durchlaufen Sie die Schlüssel der HashMap und erhalten Sie den Wert über den Schlüssel
=Integer =Inerator =map.keySet().iterator()(iterator.hasNext()) { key=(String)iterator.next()value=(Integer)map.get(key)}
(3) Durchlaufen Sie die Werte von HashMap: Der erste Schritt besteht darin, den Wertesatz basierend auf dem Wert zu erhalten und den Wertesatz iterativ zu durchlaufen
=Collection =map.values()Iterator = .iterator()(iterator.hasNext()) { value=(Integer)iterator.next()}
Häufig verwendete Funktionen:
() Object () (Object key) (Object value) Set8817e8d4bd2291481cc1067ca69329e6> () (Object key) () Seta8093152e673feb7aba1828c43532094 () (keyvalue) (Map024902c398a6aa179f04c367da6aee33 map) (Object key) () Collectiona8093152e673feb7aba1828c43532094 ()
HashMap-Beispielcode:
public class Hello { public void testHashMapAPIs() { Random r = new Random(); HashMap601754196720ae8e56f6948b6d2ab654 map = new HashMap(); map.put("one", r.nextInt(10)); map.put("two", r.nextInt(10)); map.put("three", r.nextInt(10)); System.out.println("map:"+map ); Iterator iter = map.entrySet().iterator(); while(iter.hasNext()) { Map.Entry entry = (Map.Entry)iter.next(); System.out.println("key : "+ entry.getKey() +",value:"+entry.getValue()); } System.out.println("size:"+map.size()); System.out.println("contains key two : "+map.containsKey("two")); System.out.println("contains key five : "+map.containsKey("five")); System.out.println("contains value 0 : "+map.containsValue(new Integer(0))); map.remove("three"); System.out.println("map:"+map ); map.clear(); System.out.println((map.isEmpty()?"map is empty":"map is not empty") ); } public static void main(String[] args) { Hello hello=new Hello(); hello.testHashMapAPIs(); } }
Laufergebnis:
map:{one=3, two=9, three=9} key : one,value:3 key : two,value:9 key : three,value:9 size:3 contains key two : true contains key five : false contains value 0 : false map:{one=3, two=9} map is empty
HashMap-Quellcode-Analyse in Java8:
public class HashMapb77a8d9c3c319e50d4b02a976b347910 extends AbstractMapb77a8d9c3c319e50d4b02a976b347910 implements Mapb77a8d9c3c319e50d4b02a976b347910, Cloneable, Serializable { private static final long serialVersionUID = 362498820763181265L; static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 初始大小为2的4次方 static final int MAXIMUM_CAPACITY = 1 << 30;//最大为2的30次方 static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子是0.75 static final int TREEIFY_THRESHOLD = 8; static final int UNTREEIFY_THRESHOLD = 6; static final int MIN_TREEIFY_CAPACITY = 64; //节点类 static class Nodeb77a8d9c3c319e50d4b02a976b347910 implements Map.Entryb77a8d9c3c319e50d4b02a976b347910 { final int hash; final K key; V value; Node81079595401ce1162abe0d5a660013d8 next; Node(int hash, K key, V value, Node81079595401ce1162abe0d5a660013d8 next) { this.hash = hash; this.key = key; this.value = value; this.next = next; } public final K getKey() { return key; } public final V getValue() { return value; } public final String toString() { return key + "=" + value; } public final int hashCode() { return Objects.hashCode(key) ^ Objects.hashCode(value); } public final V setValue(V newValue) { V oldValue = value; value = newValue; return oldValue; } public final boolean equals(Object o) { if (o == this) return true; if (o instanceof Map.Entry) { Map.Entryd43304c59d62d300b67a59666cfd3cea e = (Map.Entryd43304c59d62d300b67a59666cfd3cea) o; if (Objects.equals(key, e.getKey()) && Objects.equals(value, e.getValue())) return true; } return false; } } //计算Hash static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } //返回类 static Class6b3d0130bba23ae47fe2b8e8cddf0195 comparableClassFor(Object x) { if (x instanceof Comparable) { Class6b3d0130bba23ae47fe2b8e8cddf0195 c; Type[] ts, as; Type t; ParameterizedType p; if ((c = x.getClass()) == String.class) // bypass checks return c; if ((ts = c.getGenericInterfaces()) != null) { for (int i = 0; i < ts.length; ++i) { if (((t = ts[i]) instanceof ParameterizedType) && ((p = (ParameterizedType)t).getRawType() == Comparable.class) && (as = p.getActualTypeArguments()) != null && as.length == 1 && as[0] == c) // type arg is c return c; } } } return null; } @SuppressWarnings({"rawtypes","unchecked"}) // for cast to Comparable static int compareComparables(Class6b3d0130bba23ae47fe2b8e8cddf0195 kc, Object k, Object x) { return (x == null || x.getClass() != kc ? 0 : ((Comparable)k).compareTo(x)); } static final int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n 94c7772769a380812d3bd4a3f478d6e2= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1; } transient Nodeb77a8d9c3c319e50d4b02a976b347910[] table;//数据表 transient Set<Map.Entryb77a8d9c3c319e50d4b02a976b347910> entrySet;//实体集合 transient int size;//大小 transient int modCount;//用来实现fail-fast int threshold;//值为capacity * load factor final float loadFactor;//hashtable的加载因子 //构造函数,初始化容量大小和加载因子 public HashMap(int initialCapacity, float loadFactor) { if (initialCapacity c925b63a2537a1bf5bc840be8e193103 MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; if (loadFactor a085f4808830c8cb599c6b9ec9842867 m) { this.loadFactor = DEFAULT_LOAD_FACTOR; putMapEntries(m, false); } final void putMapEntries(Map11df7d36ed146da2cbbceeacbc3a1d74 m, boolean evict) { int s = m.size(); if (s > 0) { if (table == null) { // pre-size float ft = ((float)s / loadFactor) + 1.0F; int t = ((ft 2c7e39097ac59e951bf7d1d2ff347367 threshold) threshold = tableSizeFor(t); } else if (s > threshold) resize(); for (Map.Entry11df7d36ed146da2cbbceeacbc3a1d74 e : m.entrySet()) { K key = e.getKey(); V value = e.getValue(); putVal(hash(key), key, value, false, evict); } } } //返回大小 public int size() { return size; } //判断是否为空 public boolean isEmpty() { return size == 0; } //通过key获得值 public V get(Object key) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; return (e = getNode(hash(key), key)) == null ? null : e.value; } //通过hash和key获得节点 final Nodeb77a8d9c3c319e50d4b02a976b347910 getNode(int hash, Object key) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 first, e; int n; K k; if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null) { if (first.hash == hash && // always check first node ((k = first.key) == key || (key != null && key.equals(k)))) return first; if ((e = first.next) != null) { if (first instanceof TreeNode) return ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)first).getTreeNode(hash, key); do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) return e; } while ((e = e.next) != null); } } return null; } //是否含有某个key public boolean containsKey(Object key) { return getNode(hash(key), key) != null; } //如果之前存在key的value值,则替换掉 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 p; int n, i; if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Nodeb77a8d9c3c319e50d4b02a976b347910 e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)p).putTreeVal(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; } //改变大小 final Nodeb77a8d9c3c319e50d4b02a976b347910[] resize() { Nodeb77a8d9c3c319e50d4b02a976b347910[] oldTab = table; int oldCap = (oldTab == null) ? 0 : oldTab.length; int oldThr = threshold; int newCap, newThr = 0; if (oldCap > 0) { if (oldCap >= MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return oldTab; } else if ((newCap = oldCap 00a870fc5c36d70c274f6e7d254426e1= DEFAULT_INITIAL_CAPACITY) newThr = oldThr a559973318aed8bfd59cb1ded4361ff5 0) // initial capacity was placed in threshold newCap = oldThr; else { // zero initial threshold signifies using defaults newCap = DEFAULT_INITIAL_CAPACITY; newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY); } if (newThr == 0) { float ft = (float)newCap * loadFactor; newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ? (int)ft : Integer.MAX_VALUE); } threshold = newThr; @SuppressWarnings({"rawtypes","unchecked"}) Nodeb77a8d9c3c319e50d4b02a976b347910[] newTab = (Nodeb77a8d9c3c319e50d4b02a976b347910[])new Node[newCap]; table = newTab; if (oldTab != null) { for (int j = 0; j < oldCap; ++j) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; if ((e = oldTab[j]) != null) { oldTab[j] = null; if (e.next == null) newTab[e.hash & (newCap - 1)] = e; else if (e instanceof TreeNode) ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)e).split(this, newTab, j, oldCap); else { // preserve order Nodeb77a8d9c3c319e50d4b02a976b347910 loHead = null, loTail = null; Nodeb77a8d9c3c319e50d4b02a976b347910 hiHead = null, hiTail = null; Nodeb77a8d9c3c319e50d4b02a976b347910 next; do { next = e.next; if ((e.hash & oldCap) == 0) { if (loTail == null) loHead = e; else loTail.next = e; loTail = e; } else { if (hiTail == null) hiHead = e; else hiTail.next = e; hiTail = e; } } while ((e = next) != null); if (loTail != null) { loTail.next = null; newTab[j] = loHead; } if (hiTail != null) { hiTail.next = null; newTab[j + oldCap] = hiHead; } } } } } return newTab; } final void treeifyBin(Nodeb77a8d9c3c319e50d4b02a976b347910[] tab, int hash) { int n, index; Nodeb77a8d9c3c319e50d4b02a976b347910 e; if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY) resize(); else if ((e = tab[index = (n - 1) & hash]) != null) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 hd = null, tl = null; do { TreeNodeb77a8d9c3c319e50d4b02a976b347910 p = replacementTreeNode(e, null); if (tl == null) hd = p; else { p.prev = tl; tl.next = p; } tl = p; } while ((e = e.next) != null); if ((tab[index] = hd) != null) hd.treeify(tab); } } public void putAll(Map11df7d36ed146da2cbbceeacbc3a1d74 m) { putMapEntries(m, true); } public V remove(Object key) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; return (e = removeNode(hash(key), key, null, false, true)) == null ? null : e.value; } final Nodeb77a8d9c3c319e50d4b02a976b347910 removeNode(int hash, Object key, Object value, boolean matchValue, boolean movable) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 p; int n, index; if ((tab = table) != null && (n = tab.length) > 0 && (p = tab[index = (n - 1) & hash]) != null) { Nodeb77a8d9c3c319e50d4b02a976b347910 node = null, e; K k; V v; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) node = p; else if ((e = p.next) != null) { if (p instanceof TreeNode) node = ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)p).getTreeNode(hash, key); else { do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { node = e; break; } p = e; } while ((e = e.next) != null); } } if (node != null && (!matchValue || (v = node.value) == value || (value != null && value.equals(v)))) { if (node instanceof TreeNode) ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)node).removeTreeNode(this, tab, movable); else if (node == p) tab[index] = node.next; else p.next = node.next; ++modCount; --size; afterNodeRemoval(node); return node; } } return null; } public void clear() { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; modCount++; if ((tab = table) != null && size > 0) { size = 0; for (int i = 0; i < tab.length; ++i) tab[i] = null; } } public boolean containsValue(Object value) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; V v; if ((tab = table) != null && size > 0) { for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) { if ((v = e.value) == value || (value != null && value.equals(v))) return true; } } } return false; } public Set245c3adc26563b673f7297c0b3777639 keySet() { Set245c3adc26563b673f7297c0b3777639 ks; return (ks = keySet) == null ? (keySet = new KeySet()) : ks; } final class KeySet extends AbstractSet245c3adc26563b673f7297c0b3777639 { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator245c3adc26563b673f7297c0b3777639 iterator() { return new KeyIterator(); } 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 Spliterator245c3adc26563b673f7297c0b3777639 spliterator() { return new KeySpliteratora8093152e673feb7aba1828c43532094(HashMap.this, 0, -1, 0, 0); } public final void forEach(Consumer99be4058f294b5c4a6207ddd3216ce19 action) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (action == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) action.accept(e.key); } if (modCount != mc) throw new ConcurrentModificationException(); } } } public Collectiond94943c0b4933ad8cac500132f64757f values() { Collectiond94943c0b4933ad8cac500132f64757f vs; return (vs = values) == null ? (values = new Values()) : vs; } final class Values extends AbstractCollectiond94943c0b4933ad8cac500132f64757f { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iteratord94943c0b4933ad8cac500132f64757f iterator() { return new ValueIterator(); } public final boolean contains(Object o) { return containsValue(o); } public final Spliteratord94943c0b4933ad8cac500132f64757f spliterator() { return new ValueSpliteratora8093152e673feb7aba1828c43532094(HashMap.this, 0, -1, 0, 0); } public final void forEach(Consumer4b7c428692c243aad23ae950d093df01 action) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (action == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) action.accept(e.value); } if (modCount != mc) throw new ConcurrentModificationException(); } } } public Set<Map.Entryb77a8d9c3c319e50d4b02a976b347910> entrySet() { Set<Map.Entryb77a8d9c3c319e50d4b02a976b347910> es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es; } final class EntrySet extends AbstractSet<Map.Entryb77a8d9c3c319e50d4b02a976b347910> { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator<Map.Entryb77a8d9c3c319e50d4b02a976b347910> iterator() { return new EntryIterator(); } public final boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entryc3f2d894ed311a524f031af7191b9ddc e = (Map.Entryc3f2d894ed311a524f031af7191b9ddc) o; Object key = e.getKey(); Nodeb77a8d9c3c319e50d4b02a976b347910 candidate = getNode(hash(key), key); return candidate != null && candidate.equals(e); } public final boolean remove(Object o) { if (o instanceof Map.Entry) { Map.Entryc3f2d894ed311a524f031af7191b9ddc e = (Map.Entryc3f2d894ed311a524f031af7191b9ddc) o; Object key = e.getKey(); Object value = e.getValue(); return removeNode(hash(key), key, value, true, true) != null; } return false; } public final Spliterator<Map.Entryb77a8d9c3c319e50d4b02a976b347910> spliterator() { return new EntrySpliteratora8093152e673feb7aba1828c43532094(HashMap.this, 0, -1, 0, 0); } public final void forEach(Consumer<? super Map.Entryb77a8d9c3c319e50d4b02a976b347910> action) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (action == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) action.accept(e); } if (modCount != mc) throw new ConcurrentModificationException(); } } } // Overrides of JDK8 Map extension methods @Override public V getOrDefault(Object key, V defaultValue) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; return (e = getNode(hash(key), key)) == null ? defaultValue : e.value; } @Override public V putIfAbsent(K key, V value) { return putVal(hash(key), key, value, true, true); } @Override public boolean remove(Object key, Object value) { return removeNode(hash(key), key, value, true, true) != null; } @Override public boolean replace(K key, V oldValue, V newValue) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; V v; if ((e = getNode(hash(key), key)) != null && ((v = e.value) == oldValue || (v != null && v.equals(oldValue)))) { e.value = newValue; afterNodeAccess(e); return true; } return false; } @Override public V replace(K key, V value) { Nodeb77a8d9c3c319e50d4b02a976b347910 e; if ((e = getNode(hash(key), key)) != null) { V oldValue = e.value; e.value = value; afterNodeAccess(e); return oldValue; } return null; } @Override public V computeIfAbsent(K key, Functionb68c911977e56dedeb85de82f5d80518 mappingFunction) { if (mappingFunction == null) throw new NullPointerException(); int hash = hash(key); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 first; int n, i; int binCount = 0; TreeNodeb77a8d9c3c319e50d4b02a976b347910 t = null; Nodeb77a8d9c3c319e50d4b02a976b347910 old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)first).getTreeNode(hash, key); else { Nodeb77a8d9c3c319e50d4b02a976b347910 e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } V oldValue; if (old != null && (oldValue = old.value) != null) { afterNodeAccess(old); return oldValue; } } V v = mappingFunction.apply(key); if (v == null) { return null; } else if (old != null) { old.value = v; afterNodeAccess(old); return v; } else if (t != null) t.putTreeVal(this, tab, hash, key, v); else { tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); return v; } public V computeIfPresent(K key, BiFunction0a1b16d994d218d93e3e331534b14776 remappingFunction) { if (remappingFunction == null) throw new NullPointerException(); Nodeb77a8d9c3c319e50d4b02a976b347910 e; V oldValue; int hash = hash(key); if ((e = getNode(hash, key)) != null && (oldValue = e.value) != null) { V v = remappingFunction.apply(key, oldValue); if (v != null) { e.value = v; afterNodeAccess(e); return v; } else removeNode(hash, key, null, false, true); } return null; } @Override public V compute(K key, BiFunction0a1b16d994d218d93e3e331534b14776 remappingFunction) { if (remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 first; int n, i; int binCount = 0; TreeNodeb77a8d9c3c319e50d4b02a976b347910 t = null; Nodeb77a8d9c3c319e50d4b02a976b347910 old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)first).getTreeNode(hash, key); else { Nodeb77a8d9c3c319e50d4b02a976b347910 e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } } V oldValue = (old == null) ? null : old.value; V v = remappingFunction.apply(key, oldValue); if (old != null) { if (v != null) { old.value = v; afterNodeAccess(old); } else removeNode(hash, key, null, false, true); } else if (v != null) { if (t != null) t.putTreeVal(this, tab, hash, key, v); else { tab[i] = newNode(hash, key, v, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); } return v; } @Override public V merge(K key, V value, BiFunctiona9451a6954651d01dcb928f097d6d988 remappingFunction) { if (value == null) throw new NullPointerException(); if (remappingFunction == null) throw new NullPointerException(); int hash = hash(key); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; Nodeb77a8d9c3c319e50d4b02a976b347910 first; int n, i; int binCount = 0; TreeNodeb77a8d9c3c319e50d4b02a976b347910 t = null; Nodeb77a8d9c3c319e50d4b02a976b347910 old = null; if (size > threshold || (tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; if ((first = tab[i = (n - 1) & hash]) != null) { if (first instanceof TreeNode) old = (t = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)first).getTreeNode(hash, key); else { Nodeb77a8d9c3c319e50d4b02a976b347910 e = first; K k; do { if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) { old = e; break; } ++binCount; } while ((e = e.next) != null); } } if (old != null) { V v; if (old.value != null) v = remappingFunction.apply(old.value, value); else v = value; if (v != null) { old.value = v; afterNodeAccess(old); } else removeNode(hash, key, null, false, true); return v; } if (value != null) { if (t != null) t.putTreeVal(this, tab, hash, key, value); else { tab[i] = newNode(hash, key, value, first); if (binCount >= TREEIFY_THRESHOLD - 1) treeifyBin(tab, hash); } ++modCount; ++size; afterNodeInsertion(true); } return value; } @Override public void forEach(BiConsumer8d7aa65c8046027ea338ee53f830d46e action) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (action == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) action.accept(e.key, e.value); } if (modCount != mc) throw new ConcurrentModificationException(); } } @Override public void replaceAll(BiFunction0a1b16d994d218d93e3e331534b14776 function) { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (function == null) throw new NullPointerException(); if (size > 0 && (tab = table) != null) { int mc = modCount; for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) { e.value = function.apply(e.key, e.value); } } if (modCount != mc) throw new ConcurrentModificationException(); } } @SuppressWarnings("unchecked") @Override public Object clone() { HashMapb77a8d9c3c319e50d4b02a976b347910 result; try { result = (HashMapb77a8d9c3c319e50d4b02a976b347910)super.clone(); } catch (CloneNotSupportedException e) { // this shouldn't happen, since we are Cloneable throw new InternalError(e); } result.reinitialize(); result.putMapEntries(this, false); return result; } final float loadFactor() { return loadFactor; } final int capacity() { return (table != null) ? table.length : (threshold > 0) ? threshold : DEFAULT_INITIAL_CAPACITY; } private void writeObject(java.io.ObjectOutputStream s) throws IOException { int buckets = capacity(); // Write out the threshold, loadfactor, and any hidden stuff s.defaultWriteObject(); s.writeInt(buckets); s.writeInt(size); internalWriteEntries(s); } private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { // Read in the threshold (ignored), loadfactor, and any hidden stuff s.defaultReadObject(); reinitialize(); if (loadFactor 1278fa994f6e5e24aa5cbf3831adbac7 0) { // (if zero, use defaults) // Size the table using given load factor only if within // range of 0.25...4.0 float lf = Math.min(Math.max(0.25f, loadFactor), 4.0f); float fc = (float)mappings / lf + 1.0f; int cap = ((fc e3a6720a76f135d81b47e76f4e3db69a= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : tableSizeFor((int)fc)); float ft = (float)cap * lf; threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ? (int)ft : Integer.MAX_VALUE); @SuppressWarnings({"rawtypes","unchecked"}) Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = (Nodeb77a8d9c3c319e50d4b02a976b347910[])new Node[cap]; table = tab; // Read the keys and values, and put the mappings in the HashMap for (int i = 0; i < mappings; i++) { @SuppressWarnings("unchecked") K key = (K) s.readObject(); @SuppressWarnings("unchecked") V value = (V) s.readObject(); putVal(hash(key), key, value, false, false); } } } abstract class HashIterator { Nodeb77a8d9c3c319e50d4b02a976b347910 next; // next entry to return Nodeb77a8d9c3c319e50d4b02a976b347910 current; // current entry int expectedModCount; // for fast-fail int index; // current slot HashIterator() { expectedModCount = modCount; Nodeb77a8d9c3c319e50d4b02a976b347910[] t = table; current = next = null; index = 0; if (t != null && size > 0) { // advance to first entry do {} while (index < t.length && (next = t[index++]) == null); } } public final boolean hasNext() { return next != null; } final Nodeb77a8d9c3c319e50d4b02a976b347910 nextNode() { Nodeb77a8d9c3c319e50d4b02a976b347910[] t; Nodeb77a8d9c3c319e50d4b02a976b347910 e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null); } return e; } public final void remove() { Nodeb77a8d9c3c319e50d4b02a976b347910 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; } } final class KeyIterator extends HashIterator implements Iterator245c3adc26563b673f7297c0b3777639 { public final K next() { return nextNode().key; } } final class ValueIterator extends HashIterator implements Iteratord94943c0b4933ad8cac500132f64757f { public final V next() { return nextNode().value; } } final class EntryIterator extends HashIterator implements Iterator<Map.Entryb77a8d9c3c319e50d4b02a976b347910> { public final Map.Entryb77a8d9c3c319e50d4b02a976b347910 next() { return nextNode(); } } static class HashMapSpliteratorb77a8d9c3c319e50d4b02a976b347910 { final HashMapb77a8d9c3c319e50d4b02a976b347910 map; Nodeb77a8d9c3c319e50d4b02a976b347910 current; // current node int index; // current index, modified on advance/split int fence; // one past last index int est; // size estimate int expectedModCount; // for comodification checks HashMapSpliterator(HashMapb77a8d9c3c319e50d4b02a976b347910 m, int origin, int fence, int est, int expectedModCount) { this.map = m; this.index = origin; this.fence = fence; this.est = est; this.expectedModCount = expectedModCount; } final int getFence() { // initialize fence and size on first use int hi; if ((hi = fence) < 0) { HashMapb77a8d9c3c319e50d4b02a976b347910 m = map; est = m.size; expectedModCount = m.modCount; Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = m.table; hi = fence = (tab == null) ? 0 : tab.length; } return hi; } public final long estimateSize() { getFence(); // force init return (long) est; } } static final class KeySpliteratorb77a8d9c3c319e50d4b02a976b347910 extends HashMapSpliteratorb77a8d9c3c319e50d4b02a976b347910 implements Spliterator245c3adc26563b673f7297c0b3777639 { KeySpliterator(HashMapb77a8d9c3c319e50d4b02a976b347910 m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public KeySpliteratorb77a8d9c3c319e50d4b02a976b347910 trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid || current != null) ? null : new KeySpliteratora8093152e673feb7aba1828c43532094(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer99be4058f294b5c4a6207ddd3216ce19 action) { int i, hi, mc; if (action == null) throw new NullPointerException(); HashMapb77a8d9c3c319e50d4b02a976b347910 m = map; Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = m.table; if ((hi = fence) 65c2b8f09516a88ae0fd0f139eac95a1= hi && (i = index) >= 0 && (i < (index = hi) || current != null)) { Nodeb77a8d9c3c319e50d4b02a976b347910 p = current; current = null; do { if (p == null) p = tab[i++]; else { action.accept(p.key); p = p.next; } } while (p != null || i < hi); if (m.modCount != mc) throw new ConcurrentModificationException(); } } public boolean tryAdvance(Consumer99be4058f294b5c4a6207ddd3216ce19 action) { int hi; if (action == null) throw new NullPointerException(); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = map.table; if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { while (current != null || index < hi) { if (current == null) current = tab[index++]; else { K k = current.key; current = current.next; action.accept(k); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) | Spliterator.DISTINCT; } } static final class ValueSpliteratorb77a8d9c3c319e50d4b02a976b347910 extends HashMapSpliteratorb77a8d9c3c319e50d4b02a976b347910 implements Spliteratord94943c0b4933ad8cac500132f64757f { ValueSpliterator(HashMapb77a8d9c3c319e50d4b02a976b347910 m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public ValueSpliteratorb77a8d9c3c319e50d4b02a976b347910 trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid || current != null) ? null : new ValueSpliteratora8093152e673feb7aba1828c43532094(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer4b7c428692c243aad23ae950d093df01 action) { int i, hi, mc; if (action == null) throw new NullPointerException(); HashMapb77a8d9c3c319e50d4b02a976b347910 m = map; Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = m.table; if ((hi = fence) 65c2b8f09516a88ae0fd0f139eac95a1= hi && (i = index) >= 0 && (i < (index = hi) || current != null)) { Nodeb77a8d9c3c319e50d4b02a976b347910 p = current; current = null; do { if (p == null) p = tab[i++]; else { action.accept(p.value); p = p.next; } } while (p != null || i < hi); if (m.modCount != mc) throw new ConcurrentModificationException(); } } public boolean tryAdvance(Consumer4b7c428692c243aad23ae950d093df01 action) { int hi; if (action == null) throw new NullPointerException(); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = map.table; if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { while (current != null || index < hi) { if (current == null) current = tab[index++]; else { V v = current.value; current = current.next; action.accept(v); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? Spliterator.SIZED : 0); } } static final class EntrySpliteratorb77a8d9c3c319e50d4b02a976b347910 extends HashMapSpliteratorb77a8d9c3c319e50d4b02a976b347910 implements Spliterator<Map.Entryb77a8d9c3c319e50d4b02a976b347910> { EntrySpliterator(HashMapb77a8d9c3c319e50d4b02a976b347910 m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public EntrySpliteratorb77a8d9c3c319e50d4b02a976b347910 trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid || current != null) ? null : new EntrySpliteratora8093152e673feb7aba1828c43532094(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer<? super Map.Entryb77a8d9c3c319e50d4b02a976b347910> action) { int i, hi, mc; if (action == null) throw new NullPointerException(); HashMapb77a8d9c3c319e50d4b02a976b347910 m = map; Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = m.table; if ((hi = fence) 65c2b8f09516a88ae0fd0f139eac95a1= hi && (i = index) >= 0 && (i < (index = hi) || current != null)) { Nodeb77a8d9c3c319e50d4b02a976b347910 p = current; current = null; do { if (p == null) p = tab[i++]; else { action.accept(p); p = p.next; } } while (p != null || i < hi); if (m.modCount != mc) throw new ConcurrentModificationException(); } } public boolean tryAdvance(Consumer<? super Map.Entryb77a8d9c3c319e50d4b02a976b347910> action) { int hi; if (action == null) throw new NullPointerException(); Nodeb77a8d9c3c319e50d4b02a976b347910[] tab = map.table; if (tab != null && tab.length >= (hi = getFence()) && index >= 0) { while (current != null || index < hi) { if (current == null) current = tab[index++]; else { Nodeb77a8d9c3c319e50d4b02a976b347910 e = current; current = current.next; action.accept(e); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? Spliterator.SIZED : 0) | Spliterator.DISTINCT; } } Nodeb77a8d9c3c319e50d4b02a976b347910 newNode(int hash, K key, V value, Nodeb77a8d9c3c319e50d4b02a976b347910 next) { return new Nodea8093152e673feb7aba1828c43532094(hash, key, value, next); } // For conversion from TreeNodes to plain nodes Nodeb77a8d9c3c319e50d4b02a976b347910 replacementNode(Nodeb77a8d9c3c319e50d4b02a976b347910 p, Nodeb77a8d9c3c319e50d4b02a976b347910 next) { return new Nodea8093152e673feb7aba1828c43532094(p.hash, p.key, p.value, next); } // Create a tree bin node TreeNodeb77a8d9c3c319e50d4b02a976b347910 newTreeNode(int hash, K key, V value, Nodeb77a8d9c3c319e50d4b02a976b347910 next) { return new TreeNodea8093152e673feb7aba1828c43532094(hash, key, value, next); } // For treeifyBin TreeNodeb77a8d9c3c319e50d4b02a976b347910 replacementTreeNode(Nodeb77a8d9c3c319e50d4b02a976b347910 p, Nodeb77a8d9c3c319e50d4b02a976b347910 next) { return new TreeNodea8093152e673feb7aba1828c43532094(p.hash, p.key, p.value, next); } void reinitialize() { table = null; entrySet = null; keySet = null; values = null; modCount = 0; threshold = 0; size = 0; } // Callbacks to allow LinkedHashMap post-actions void afterNodeAccess(Nodeb77a8d9c3c319e50d4b02a976b347910 p) { } void afterNodeInsertion(boolean evict) { } void afterNodeRemoval(Nodeb77a8d9c3c319e50d4b02a976b347910 p) { } // Called only from writeObject, to ensure compatible ordering. void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException { Nodeb77a8d9c3c319e50d4b02a976b347910[] tab; if (size > 0 && (tab = table) != null) { for (int i = 0; i < tab.length; ++i) { for (Nodeb77a8d9c3c319e50d4b02a976b347910 e = tab[i]; e != null; e = e.next) { s.writeObject(e.key); s.writeObject(e.value); } } } } static final class TreeNodeb77a8d9c3c319e50d4b02a976b347910 extends LinkedHashMap.Entryb77a8d9c3c319e50d4b02a976b347910 { TreeNodeb77a8d9c3c319e50d4b02a976b347910 parent; // red-black tree links TreeNodeb77a8d9c3c319e50d4b02a976b347910 left; TreeNodeb77a8d9c3c319e50d4b02a976b347910 right; TreeNodeb77a8d9c3c319e50d4b02a976b347910 prev; // needed to unlink next upon deletion boolean red; TreeNode(int hash, K key, V val, Nodeb77a8d9c3c319e50d4b02a976b347910 next) { super(hash, key, val, next); } /** * Returns root of tree containing this node. */ final TreeNodeb77a8d9c3c319e50d4b02a976b347910 root() { for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 r = this, p;;) { if ((p = r.parent) == null) return r; r = p; } } /** * Ensures that the given root is the first node of its bin. */ static b77a8d9c3c319e50d4b02a976b347910 void moveRootToFront(Nodeb77a8d9c3c319e50d4b02a976b347910[] tab, TreeNodeb77a8d9c3c319e50d4b02a976b347910 root) { int n; if (root != null && tab != null && (n = tab.length) > 0) { int index = (n - 1) & root.hash; TreeNodeb77a8d9c3c319e50d4b02a976b347910 first = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)tab[index]; if (root != first) { Nodeb77a8d9c3c319e50d4b02a976b347910 rn; tab[index] = root; TreeNodeb77a8d9c3c319e50d4b02a976b347910 rp = root.prev; if ((rn = root.next) != null) ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)rn).prev = rp; if (rp != null) rp.next = rn; if (first != null) first.prev = root; root.next = first; root.prev = null; } assert checkInvariants(root); } } final TreeNodeb77a8d9c3c319e50d4b02a976b347910 find(int h, Object k, Class6b3d0130bba23ae47fe2b8e8cddf0195 kc) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 p = this; do { int ph, dir; K pk; TreeNodeb77a8d9c3c319e50d4b02a976b347910 pl = p.left, pr = p.right, q; if ((ph = p.hash) > h) p = pl; else if (ph < h) p = pr; else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if (pl == null) p = pr; else if (pr == null) p = pl; else if ((kc != null || (kc = comparableClassFor(k)) != null) && (dir = compareComparables(kc, k, pk)) != 0) p = (dir < 0) ? pl : pr; else if ((q = pr.find(h, k, kc)) != null) return q; else p = pl; } while (p != null); return null; } final TreeNodeb77a8d9c3c319e50d4b02a976b347910 getTreeNode(int h, Object k) { return ((parent != null) ? root() : this).find(h, k, null); } static int tieBreakOrder(Object a, Object b) { int d; if (a == null || b == null || (d = a.getClass().getName(). compareTo(b.getClass().getName())) == 0) d = (System.identityHashCode(a) <= System.identityHashCode(b) ? -1 : 1); return d; } final void treeify(Nodeb77a8d9c3c319e50d4b02a976b347910[] tab) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 root = null; for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 x = this, next; x != null; x = next) { next = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)x.next; x.left = x.right = null; if (root == null) { x.parent = null; x.red = false; root = x; } else { K k = x.key; int h = x.hash; Class6b3d0130bba23ae47fe2b8e8cddf0195 kc = null; for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 p = root;;) { int dir, ph; K pk = p.key; if ((ph = p.hash) > h) dir = -1; else if (ph < h) dir = 1; else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) dir = tieBreakOrder(k, pk); TreeNodeb77a8d9c3c319e50d4b02a976b347910 xp = p; if ((p = (dir <= 0) ? p.left : p.right) == null) { x.parent = xp; if (dir <= 0) xp.left = x; else xp.right = x; root = balanceInsertion(root, x); break; } } } } moveRootToFront(tab, root); } final Nodeb77a8d9c3c319e50d4b02a976b347910 untreeify(HashMapb77a8d9c3c319e50d4b02a976b347910 map) { Nodeb77a8d9c3c319e50d4b02a976b347910 hd = null, tl = null; for (Nodeb77a8d9c3c319e50d4b02a976b347910 q = this; q != null; q = q.next) { Nodeb77a8d9c3c319e50d4b02a976b347910 p = map.replacementNode(q, null); if (tl == null) hd = p; else tl.next = p; tl = p; } return hd; } final TreeNodeb77a8d9c3c319e50d4b02a976b347910 putTreeVal(HashMapb77a8d9c3c319e50d4b02a976b347910 map, Nodeb77a8d9c3c319e50d4b02a976b347910[] tab, int h, K k, V v) { Class6b3d0130bba23ae47fe2b8e8cddf0195 kc = null; boolean searched = false; TreeNodeb77a8d9c3c319e50d4b02a976b347910 root = (parent != null) ? root() : this; for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 p = root;;) { int dir, ph; K pk; if ((ph = p.hash) > h) dir = -1; else if (ph < h) dir = 1; else if ((pk = p.key) == k || (k != null && k.equals(pk))) return p; else if ((kc == null && (kc = comparableClassFor(k)) == null) || (dir = compareComparables(kc, k, pk)) == 0) { if (!searched) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 q, ch; searched = true; if (((ch = p.left) != null && (q = ch.find(h, k, kc)) != null) || ((ch = p.right) != null && (q = ch.find(h, k, kc)) != null)) return q; } dir = tieBreakOrder(k, pk); } TreeNodeb77a8d9c3c319e50d4b02a976b347910 xp = p; if ((p = (dir <= 0) ? p.left : p.right) == null) { Nodeb77a8d9c3c319e50d4b02a976b347910 xpn = xp.next; TreeNodeb77a8d9c3c319e50d4b02a976b347910 x = map.newTreeNode(h, k, v, xpn); if (dir <= 0) xp.left = x; else xp.right = x; xp.next = x; x.parent = x.prev = xp; if (xpn != null) ((TreeNodeb77a8d9c3c319e50d4b02a976b347910)xpn).prev = x; moveRootToFront(tab, balanceInsertion(root, x)); return null; } } } final void removeTreeNode(HashMapb77a8d9c3c319e50d4b02a976b347910 map, Nodeb77a8d9c3c319e50d4b02a976b347910[] tab, boolean movable) { int n; if (tab == null || (n = tab.length) == 0) return; int index = (n - 1) & hash; TreeNodeb77a8d9c3c319e50d4b02a976b347910 first = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)tab[index], root = first, rl; TreeNodeb77a8d9c3c319e50d4b02a976b347910 succ = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)next, pred = prev; if (pred == null) tab[index] = first = succ; else pred.next = succ; if (succ != null) succ.prev = pred; if (first == null) return; if (root.parent != null) root = root.root(); if (root == null || root.right == null || (rl = root.left) == null || rl.left == null) { tab[index] = first.untreeify(map); // too small return; } TreeNodeb77a8d9c3c319e50d4b02a976b347910 p = this, pl = left, pr = right, replacement; if (pl != null && pr != null) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 s = pr, sl; while ((sl = s.left) != null) // find successor s = sl; boolean c = s.red; s.red = p.red; p.red = c; // swap colors TreeNodeb77a8d9c3c319e50d4b02a976b347910 sr = s.right; TreeNodeb77a8d9c3c319e50d4b02a976b347910 pp = p.parent; if (s == pr) { // p was s's direct parent p.parent = s; s.right = p; } else { TreeNodeb77a8d9c3c319e50d4b02a976b347910 sp = s.parent; if ((p.parent = sp) != null) { if (s == sp.left) sp.left = p; else sp.right = p; } if ((s.right = pr) != null) pr.parent = s; } p.left = null; if ((p.right = sr) != null) sr.parent = p; if ((s.left = pl) != null) pl.parent = s; if ((s.parent = pp) == null) root = s; else if (p == pp.left) pp.left = s; else pp.right = s; if (sr != null) replacement = sr; else replacement = p; } else if (pl != null) replacement = pl; else if (pr != null) replacement = pr; else replacement = p; if (replacement != p) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 pp = replacement.parent = p.parent; if (pp == null) root = replacement; else if (p == pp.left) pp.left = replacement; else pp.right = replacement; p.left = p.right = p.parent = null; } TreeNodeb77a8d9c3c319e50d4b02a976b347910 r = p.red ? root : balanceDeletion(root, replacement); if (replacement == p) { // detach TreeNodeb77a8d9c3c319e50d4b02a976b347910 pp = p.parent; p.parent = null; if (pp != null) { if (p == pp.left) pp.left = null; else if (p == pp.right) pp.right = null; } } if (movable) moveRootToFront(tab, r); } final void split(HashMapb77a8d9c3c319e50d4b02a976b347910 map, Nodeb77a8d9c3c319e50d4b02a976b347910[] tab, int index, int bit) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 b = this; // Relink into lo and hi lists, preserving order TreeNodeb77a8d9c3c319e50d4b02a976b347910 loHead = null, loTail = null; TreeNodeb77a8d9c3c319e50d4b02a976b347910 hiHead = null, hiTail = null; int lc = 0, hc = 0; for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 e = b, next; e != null; e = next) { next = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)e.next; e.next = null; if ((e.hash & bit) == 0) { if ((e.prev = loTail) == null) loHead = e; else loTail.next = e; loTail = e; ++lc; } else { if ((e.prev = hiTail) == null) hiHead = e; else hiTail.next = e; hiTail = e; ++hc; } } if (loHead != null) { if (lc <= UNTREEIFY_THRESHOLD) tab[index] = loHead.untreeify(map); else { tab[index] = loHead; if (hiHead != null) // (else is already treeified) loHead.treeify(tab); } } if (hiHead != null) { if (hc <= UNTREEIFY_THRESHOLD) tab[index + bit] = hiHead.untreeify(map); else { tab[index + bit] = hiHead; if (loHead != null) hiHead.treeify(tab); } } } /* ------------------------------------------------------------ */ // Red-black tree methods, all adapted from CLR static b77a8d9c3c319e50d4b02a976b347910 TreeNodeb77a8d9c3c319e50d4b02a976b347910 rotateLeft(TreeNodeb77a8d9c3c319e50d4b02a976b347910 root, TreeNodeb77a8d9c3c319e50d4b02a976b347910 p) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 r, pp, rl; if (p != null && (r = p.right) != null) { if ((rl = p.right = r.left) != null) rl.parent = p; if ((pp = r.parent = p.parent) == null) (root = r).red = false; else if (pp.left == p) pp.left = r; else pp.right = r; r.left = p; p.parent = r; } return root; } static b77a8d9c3c319e50d4b02a976b347910 TreeNodeb77a8d9c3c319e50d4b02a976b347910 rotateRight(TreeNodeb77a8d9c3c319e50d4b02a976b347910 root, TreeNodeb77a8d9c3c319e50d4b02a976b347910 p) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 l, pp, lr; if (p != null && (l = p.left) != null) { if ((lr = p.left = l.right) != null) lr.parent = p; if ((pp = l.parent = p.parent) == null) (root = l).red = false; else if (pp.right == p) pp.right = l; else pp.left = l; l.right = p; p.parent = l; } return root; } static b77a8d9c3c319e50d4b02a976b347910 TreeNodeb77a8d9c3c319e50d4b02a976b347910 balanceInsertion(TreeNodeb77a8d9c3c319e50d4b02a976b347910 root, TreeNodeb77a8d9c3c319e50d4b02a976b347910 x) { x.red = true; for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 xp, xpp, xppl, xppr;;) { if ((xp = x.parent) == null) { x.red = false; return x; } else if (!xp.red || (xpp = xp.parent) == null) return root; if (xp == (xppl = xpp.left)) { if ((xppr = xpp.right) != null && xppr.red) { xppr.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.right) { root = rotateLeft(root, x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; root = rotateRight(root, xpp); } } } } else { if (xppl != null && xppl.red) { xppl.red = false; xp.red = false; xpp.red = true; x = xpp; } else { if (x == xp.left) { root = rotateRight(root, x = xp); xpp = (xp = x.parent) == null ? null : xp.parent; } if (xp != null) { xp.red = false; if (xpp != null) { xpp.red = true; root = rotateLeft(root, xpp); } } } } } } static b77a8d9c3c319e50d4b02a976b347910 TreeNodeb77a8d9c3c319e50d4b02a976b347910 balanceDeletion(TreeNodeb77a8d9c3c319e50d4b02a976b347910 root, TreeNodeb77a8d9c3c319e50d4b02a976b347910 x) { for (TreeNodeb77a8d9c3c319e50d4b02a976b347910 xp, xpl, xpr;;) { if (x == null || x == root) return root; else if ((xp = x.parent) == null) { x.red = false; return x; } else if (x.red) { x.red = false; return root; } else if ((xpl = xp.left) == x) { if ((xpr = xp.right) != null && xpr.red) { xpr.red = false; xp.red = true; root = rotateLeft(root, xp); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr == null) x = xp; else { TreeNodeb77a8d9c3c319e50d4b02a976b347910 sl = xpr.left, sr = xpr.right; if ((sr == null || !sr.red) && (sl == null || !sl.red)) { xpr.red = true; x = xp; } else { if (sr == null || !sr.red) { if (sl != null) sl.red = false; xpr.red = true; root = rotateRight(root, xpr); xpr = (xp = x.parent) == null ? null : xp.right; } if (xpr != null) { xpr.red = (xp == null) ? false : xp.red; if ((sr = xpr.right) != null) sr.red = false; } if (xp != null) { xp.red = false; root = rotateLeft(root, xp); } x = root; } } } else { // symmetric if (xpl != null && xpl.red) { xpl.red = false; xp.red = true; root = rotateRight(root, xp); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl == null) x = xp; else { TreeNodeb77a8d9c3c319e50d4b02a976b347910 sl = xpl.left, sr = xpl.right; if ((sl == null || !sl.red) && (sr == null || !sr.red)) { xpl.red = true; x = xp; } else { if (sl == null || !sl.red) { if (sr != null) sr.red = false; xpl.red = true; root = rotateLeft(root, xpl); xpl = (xp = x.parent) == null ? null : xp.left; } if (xpl != null) { xpl.red = (xp == null) ? false : xp.red; if ((sl = xpl.left) != null) sl.red = false; } if (xp != null) { xp.red = false; root = rotateRight(root, xp); } x = root; } } } } } /** * Recursive invariant check */ static b77a8d9c3c319e50d4b02a976b347910 boolean checkInvariants(TreeNodeb77a8d9c3c319e50d4b02a976b347910 t) { TreeNodeb77a8d9c3c319e50d4b02a976b347910 tp = t.parent, tl = t.left, tr = t.right, tb = t.prev, tn = (TreeNodeb77a8d9c3c319e50d4b02a976b347910)t.next; if (tb != null && tb.next != t) return false; if (tn != null && tn.prev != t) return false; if (tp != null && t != tp.left && t != tp.right) return false; if (tl != null && (tl.parent != t || tl.hash > t.hash)) return false; if (tr != null && (tr.parent != t || tr.hash < t.hash)) return false; if (t.red && tl != null && tl.red && tr != null && tr.red) return false; if (tl != null && !checkInvariants(tl)) return false; if (tr != null && !checkInvariants(tr)) return false; return true; } } }
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung von HashMap in Java-Sammlungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!