>  기사  >  Java  >  Java 컬렉션의 HashMap에 대한 자세한 설명

Java 컬렉션의 HashMap에 대한 자세한 설명

黄舟
黄舟원래의
2017-03-13 17:42:371445검색

HashMap은 해시 테이블이고 저장된 콘텐츠는 키-값 매핑입니다. HashMap은 AbstractMap을 상속하고 Map, Cloneable 및 Serialized 인터페이스를 구현합니다.

(1) HashMap은 스레드로부터 안전하지 않으며 키-값은 null일 수 있으며 순서가 지정되지 않습니다.

(2) HashMap의 초기 크기는 16이고, 최대 크기는 2의 30승이며, 기본 로딩 인자는 0.75입니다.

(3) 초기 용량은 해시 테이블이 생성될 당시의 용량일 뿐이며, 로드 팩터는 해시 테이블이 자동으로 증가하기 전까지 해시 테이블이 얼마나 가득 찰 수 있는지를 나타내는 척도입니다. 해시 테이블의 항목 수가 부하율과 현재 용량의 곱을 초과하는 경우 해시 테이블을 다시 해시해야 합니다(내부 데이터 구조 재구성)


HashMap과 Map의 관계는 다음과 같습니다.


(1) HashMap은 AbstractMap 클래스를 상속하고 Map 인터페이스를 구현합니다.

(2) HashMap은 지퍼 방식을 통해 해시 테이블을 구현합니다. 몇 가지 중요한 멤버 변수는 table, size, Threshold, loadFactor, modCount입니다.

테이블은 Entry[] 배열 유형입니다. 항목은 실제로 HashMap의 키-값이 이 배열에 저장됩니다.

size는 HashMap의 크기로, HashMap에 저장된 키-값 쌍의 개수입니다.

threshold는 HashMap의 용량을 조정해야 하는지 여부를 결정하는 데 사용되는 임계값입니다. 임계값을 초과하면 HashMap의 용량을 두 배로 늘려야 합니다.

loadFactor 로드 팩터

modCount는 빠른 실패 메커니즘을 구현하는 데 사용됩니다.


HashMap 순회 방법:

(1) HashMap의 키-값 쌍 순회: 첫 번째 단계는 EntrySet( ) 함수, 두 번째 단계는 Iterator 반복자를 통해 항목 컬렉션을 순회하여

Integer Iterator =map.entrySet().iterator()(iterator.hasNext())
 {
        Map.Entry entry=(Map.Entry)iterator.next()key=(String)enrty.getKey()value=(Integer)entry.getValue()}


데이터를 얻는 것입니다. (2) HashMap의 키를 순회하고 다음을 통해 값을 얻습니다. 키

=Integer =Inerator =map.keySet().iterator()(iterator.hasNext())
{
        key=(String)iterator.next()value=(Integer)map.get(key)}

(3) HashMap의 값 순회: 첫 번째 단계는 값을 기준으로 설정된 값을 얻고,

=Collection =map.values()Iterator = .iterator()(iterator.hasNext())
{
    value=(Integer)iterator.next()}


자주 사용하는 기능:


()
Object               ()
(Object key)
(Object value)
Set8817e8d4bd2291481cc1067ca69329e6>     ()
(Object key)
()
Seta8093152e673feb7aba1828c43532094               ()
(keyvalue)
(Map024902c398a6aa179f04c367da6aee33 map)
(Object key)
()
Collectiona8093152e673feb7aba1828c43532094        ()
HashMap 샘플 코드:


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();
    }
}


실행 결과:

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


Java8의 HashMap 소스 코드 분석:


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;
        }
    }

}

위 내용은 Java 컬렉션의 HashMap에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.