Heim >Java >javaLernprogramm >Detaillierte Erläuterung von HashMap in Java-Sammlungen

Detaillierte Erläuterung von HashMap in Java-Sammlungen

黄舟
黄舟Original
2017-03-13 17:42:371503Durchsuche

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn