Java集合之HashMap

来源:互联网 发布:安卓简单捕鱼源码 编辑:程序博客网 时间:2024/04/30 15:29
HashMap是一个散列表,存储的内容是键值对(key-value)映射。HashMap继承于AbstractMap并实现了Map、Cloneable、Serializable接口。
(1)HashMap不是线程安全的,同时key-value都可以为null,并且是无序的。
(2)HashMap的初始大小为16,最大大小为2的30次方,默认的加载因子是0.75。
(3)初始容量只是哈希表在创建时的容量,加载因子是哈希表在其容量自动增加之前可以达到多满的一种尺度。当哈希表中的条目数超出了加载因子与当前容量的乘积时,就需要对该哈希表进行rehash操作(重建内部的数据结构)

HashMap与Map关系如下:

(1)HashMap继承于AbstractMap类,实现了Map接口。
(2)HashMap通过拉链法实现哈希表。几个重要的成员变量有:table,size,threshold,loadFactor,modCount。
table是一个Entry[]数组类型,Entry实际上是一个单向链表,HashMap的key-value都存储在这个数组中。
size是HashMap的大小,它是HashMap保存的键值对的数量。
threshold是HashMap的阈值,用于判断是否需要调整HashMap的容量,threshold的值等于容量乘以加载因子,当HashMap中存储的数据达到threshold时,就需要将HashMap的容量加倍。
loadFactor加载因子
modCount用来实现fail-fast机制。

HashMap的遍历方式:
(1)遍历HashMap的键值对:第一步是获得通过entrySet()函数获得entry集合,第二步通过Iterator迭代器遍历entry集合获得数据
Stringkey;
Integer value;
Iterator iterator=map.entrySet().iterator();
while(iterator.hasNext())
{
Map.Entry entry=(Map.Entry)iterator.next();
key=(String)enrty.getKey();
value=(Integer)entry.getValue();
}

(2)遍历HashMap的键,通过key来获得value
Stringkey=null;
Integer value=null;
Inerator iterator=map.keySet().iterator();
while(iterator.hasNext())
{
key=(String)iterator.next();
value=(Integer)map.get(key);
}
(3)遍历HashMap的值:第一步根据value获得值集合,对值集合进行迭代遍历
Integervalue=null;
Collection c=map.values();
Iterator iterator = c.iterator();
while(iterator.hasNext())
{
value=(Integer)iterator.next();
}

常用的函数:
void                 clear()
Object clone()
boolean containsKey(Object key)
boolean containsValue(Object value)
Set<Entry<K, V>> entrySet()
V get(Object key)
boolean isEmpty()
Set<K> keySet()
V put(K key, V value)
void putAll(Map<? extends K, ? extends V> map)
V remove(Object key)
int size()
Collection<V> values()

HashMap示例代码:
public class Hello {    public void testHashMapAPIs()    {        Random r = new Random();        HashMap<String,Integer> 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 HashMap<K,V> extends AbstractMap<K,V>        implements Map<K,V>, 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 Node<K,V> implements Map.Entry<K,V> {        final int hash;        final K key;        V value;        Node<K, V> next;        Node(int hash, K key, V value, Node<K, V> 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.Entry<?, ?> e = (Map.Entry<?, ?>) 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 Class<?> comparableClassFor(Object x) {        if (x instanceof Comparable) {            Class<?> 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(Class<?> 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 < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;    }    transient Node<K,V>[] table;//数据表    transient Set<Map.Entry<K,V>> 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 < 0)            throw new IllegalArgumentException("Illegal initial capacity: " +                    initialCapacity);        if (initialCapacity > MAXIMUM_CAPACITY)            initialCapacity = MAXIMUM_CAPACITY;        if (loadFactor <= 0 || Float.isNaN(loadFactor))            throw new IllegalArgumentException("Illegal load factor: " +                    loadFactor);        this.loadFactor = loadFactor;        this.threshold = tableSizeFor(initialCapacity);    }    //构造函数 初始化大小    public HashMap(int initialCapacity) {        this(initialCapacity, DEFAULT_LOAD_FACTOR);    }    //使用默认的加载因子    public HashMap() {        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted    }    public HashMap(Map<? extends K, ? extends V> m) {        this.loadFactor = DEFAULT_LOAD_FACTOR;        putMapEntries(m, false);    }    final void putMapEntries(Map<? extends K, ? extends V> 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 < (float)MAXIMUM_CAPACITY) ?                        (int)ft : MAXIMUM_CAPACITY);                if (t > threshold)                    threshold = tableSizeFor(t);            }            else if (s > threshold)                resize();            for (Map.Entry<? extends K, ? extends V> 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) {        Node<K,V> e;        return (e = getNode(hash(key), key)) == null ? null : e.value;    }    //通过hash和key获得节点    final Node<K,V> getNode(int hash, Object key) {        Node<K,V>[] tab; Node<K,V> 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 ((TreeNode<K,V>)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) {        Node<K,V>[] tab; Node<K,V> 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 {            Node<K,V> e; K k;            if (p.hash == hash &&                    ((k = p.key) == key || (key != null && key.equals(k))))                e = p;            else if (p instanceof TreeNode)                e = ((TreeNode<K,V>)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 Node<K,V>[] resize() {        Node<K,V>[] 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 << 1) < MAXIMUM_CAPACITY &&                    oldCap >= DEFAULT_INITIAL_CAPACITY)                newThr = oldThr << 1; // double threshold        }        else if (oldThr > 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"})        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];        table = newTab;        if (oldTab != null) {            for (int j = 0; j < oldCap; ++j) {                Node<K,V> e;                if ((e = oldTab[j]) != null) {                    oldTab[j] = null;                    if (e.next == null)                        newTab[e.hash & (newCap - 1)] = e;                    else if (e instanceof TreeNode)                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);                    else { // preserve order                        Node<K,V> loHead = null, loTail = null;                        Node<K,V> hiHead = null, hiTail = null;                        Node<K,V> 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(Node<K,V>[] tab, int hash) {        int n, index; Node<K,V> e;        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)            resize();        else if ((e = tab[index = (n - 1) & hash]) != null) {            TreeNode<K,V> hd = null, tl = null;            do {                TreeNode<K,V> 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(Map<? extends K, ? extends V> m) {        putMapEntries(m, true);    }    public V remove(Object key) {        Node<K,V> e;        return (e = removeNode(hash(key), key, null, false, true)) == null ?                null : e.value;    }    final Node<K,V> removeNode(int hash, Object key, Object value,                               boolean matchValue, boolean movable) {        Node<K,V>[] tab; Node<K,V> p; int n, index;        if ((tab = table) != null && (n = tab.length) > 0 &&                (p = tab[index = (n - 1) & hash]) != null) {            Node<K,V> 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 = ((TreeNode<K,V>)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)                    ((TreeNode<K,V>)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() {        Node<K,V>[] 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) {        Node<K,V>[] tab; V v;        if ((tab = table) != null && size > 0) {            for (int i = 0; i < tab.length; ++i) {                for (Node<K,V> e = tab[i]; e != null; e = e.next) {                    if ((v = e.value) == value ||                            (value != null && value.equals(v)))                        return true;                }            }        }        return false;    }    public Set<K> keySet() {        Set<K> ks;        return (ks = keySet) == null ? (keySet = new KeySet()) : ks;    }    final class KeySet extends AbstractSet<K> {        public final int size()                 { return size; }        public final void clear()               { HashMap.this.clear(); }        public final Iterator<K> 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 Spliterator<K> spliterator() {            return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0);        }        public final void forEach(Consumer<? super K> action) {            Node<K,V>[] 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 (Node<K,V> e = tab[i]; e != null; e = e.next)                        action.accept(e.key);                }                if (modCount != mc)                    throw new ConcurrentModificationException();            }        }    }    public Collection<V> values() {        Collection<V> vs;        return (vs = values) == null ? (values = new Values()) : vs;    }    final class Values extends AbstractCollection<V> {        public final int size()                 { return size; }        public final void clear()               { HashMap.this.clear(); }        public final Iterator<V> iterator()     { return new ValueIterator(); }        public final boolean contains(Object o) { return containsValue(o); }        public final Spliterator<V> spliterator() {            return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);        }        public final void forEach(Consumer<? super V> action) {            Node<K,V>[] 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 (Node<K,V> e = tab[i]; e != null; e = e.next)                        action.accept(e.value);                }                if (modCount != mc)                    throw new ConcurrentModificationException();            }        }    }    public Set<Map.Entry<K,V>> entrySet() {        Set<Map.Entry<K,V>> es;        return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;    }    final class EntrySet extends AbstractSet<Map.Entry<K,V>> {        public final int size()                 { return size; }        public final void clear()               { HashMap.this.clear(); }        public final Iterator<Map.Entry<K,V>> iterator() {            return new EntryIterator();        }        public final boolean contains(Object o) {            if (!(o instanceof Map.Entry))                return false;            Map.Entry<?,?> e = (Map.Entry<?,?>) o;            Object key = e.getKey();            Node<K,V> candidate = getNode(hash(key), key);            return candidate != null && candidate.equals(e);        }        public final boolean remove(Object o) {            if (o instanceof Map.Entry) {                Map.Entry<?,?> e = (Map.Entry<?,?>) o;                Object key = e.getKey();                Object value = e.getValue();                return removeNode(hash(key), key, value, true, true) != null;            }            return false;        }        public final Spliterator<Map.Entry<K,V>> spliterator() {            return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);        }        public final void forEach(Consumer<? super Map.Entry<K,V>> action) {            Node<K,V>[] 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 (Node<K,V> 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) {        Node<K,V> 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) {        Node<K,V> 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) {        Node<K,V> 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,                             Function<? super K, ? extends V> mappingFunction) {        if (mappingFunction == null)            throw new NullPointerException();        int hash = hash(key);        Node<K,V>[] tab; Node<K,V> first; int n, i;        int binCount = 0;        TreeNode<K,V> t = null;        Node<K,V> 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 = (TreeNode<K,V>)first).getTreeNode(hash, key);            else {                Node<K,V> 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,                              BiFunction<? super K, ? super V, ? extends V> remappingFunction) {        if (remappingFunction == null)            throw new NullPointerException();        Node<K,V> 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,                     BiFunction<? super K, ? super V, ? extends V> remappingFunction) {        if (remappingFunction == null)            throw new NullPointerException();        int hash = hash(key);        Node<K,V>[] tab; Node<K,V> first; int n, i;        int binCount = 0;        TreeNode<K,V> t = null;        Node<K,V> 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 = (TreeNode<K,V>)first).getTreeNode(hash, key);            else {                Node<K,V> 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,                   BiFunction<? super V, ? super V, ? extends V> remappingFunction) {        if (value == null)            throw new NullPointerException();        if (remappingFunction == null)            throw new NullPointerException();        int hash = hash(key);        Node<K,V>[] tab; Node<K,V> first; int n, i;        int binCount = 0;        TreeNode<K,V> t = null;        Node<K,V> 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 = (TreeNode<K,V>)first).getTreeNode(hash, key);            else {                Node<K,V> 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(BiConsumer<? super K, ? super V> action) {        Node<K,V>[] 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 (Node<K,V> e = tab[i]; e != null; e = e.next)                    action.accept(e.key, e.value);            }            if (modCount != mc)                throw new ConcurrentModificationException();        }    }    @Override    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {        Node<K,V>[] 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 (Node<K,V> 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() {        HashMap<K,V> result;        try {            result = (HashMap<K,V>)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 <= 0 || Float.isNaN(loadFactor))            throw new InvalidObjectException("Illegal load factor: " +                    loadFactor);        s.readInt();                // Read and ignore number of buckets        int mappings = s.readInt(); // Read number of mappings (size)        if (mappings < 0)            throw new InvalidObjectException("Illegal mappings count: " +                    mappings);        else if (mappings > 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 < DEFAULT_INITIAL_CAPACITY) ?                    DEFAULT_INITIAL_CAPACITY :                    (fc >= 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"})            Node<K,V>[] tab = (Node<K,V>[])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 {        Node<K,V> next;        // next entry to return        Node<K,V> current;     // current entry        int expectedModCount;  // for fast-fail        int index;             // current slot        HashIterator() {            expectedModCount = modCount;            Node<K,V>[] 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 Node<K,V> nextNode() {            Node<K,V>[] t;            Node<K,V> 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() {            Node<K,V> 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 Iterator<K> {        public final K next() { return nextNode().key; }    }    final class ValueIterator extends HashIterator            implements Iterator<V> {        public final V next() { return nextNode().value; }    }    final class EntryIterator extends HashIterator            implements Iterator<Map.Entry<K,V>> {        public final Map.Entry<K,V> next() { return nextNode(); }    }    static class HashMapSpliterator<K,V> {        final HashMap<K,V> map;        Node<K,V> 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(HashMap<K,V> 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) {                HashMap<K,V> m = map;                est = m.size;                expectedModCount = m.modCount;                Node<K,V>[] 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 KeySpliterator<K,V>            extends HashMapSpliterator<K,V>            implements Spliterator<K> {        KeySpliterator(HashMap<K,V> m, int origin, int fence, int est,                       int expectedModCount) {            super(m, origin, fence, est, expectedModCount);        }        public KeySpliterator<K,V> trySplit() {            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;            return (lo >= mid || current != null) ? null :                    new KeySpliterator<>(map, lo, index = mid, est >>>= 1,                            expectedModCount);        }        public void forEachRemaining(Consumer<? super K> action) {            int i, hi, mc;            if (action == null)                throw new NullPointerException();            HashMap<K,V> m = map;            Node<K,V>[] tab = m.table;            if ((hi = fence) < 0) {                mc = expectedModCount = m.modCount;                hi = fence = (tab == null) ? 0 : tab.length;            }            else                mc = expectedModCount;            if (tab != null && tab.length >= hi &&                    (i = index) >= 0 && (i < (index = hi) || current != null)) {                Node<K,V> 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(Consumer<? super K> action) {            int hi;            if (action == null)                throw new NullPointerException();            Node<K,V>[] 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 ValueSpliterator<K,V>            extends HashMapSpliterator<K,V>            implements Spliterator<V> {        ValueSpliterator(HashMap<K,V> m, int origin, int fence, int est,                         int expectedModCount) {            super(m, origin, fence, est, expectedModCount);        }        public ValueSpliterator<K,V> trySplit() {            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;            return (lo >= mid || current != null) ? null :                    new ValueSpliterator<>(map, lo, index = mid, est >>>= 1,                            expectedModCount);        }        public void forEachRemaining(Consumer<? super V> action) {            int i, hi, mc;            if (action == null)                throw new NullPointerException();            HashMap<K,V> m = map;            Node<K,V>[] tab = m.table;            if ((hi = fence) < 0) {                mc = expectedModCount = m.modCount;                hi = fence = (tab == null) ? 0 : tab.length;            }            else                mc = expectedModCount;            if (tab != null && tab.length >= hi &&                    (i = index) >= 0 && (i < (index = hi) || current != null)) {                Node<K,V> 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(Consumer<? super V> action) {            int hi;            if (action == null)                throw new NullPointerException();            Node<K,V>[] 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 EntrySpliterator<K,V>            extends HashMapSpliterator<K,V>            implements Spliterator<Map.Entry<K,V>> {        EntrySpliterator(HashMap<K,V> m, int origin, int fence, int est,                         int expectedModCount) {            super(m, origin, fence, est, expectedModCount);        }        public EntrySpliterator<K,V> trySplit() {            int hi = getFence(), lo = index, mid = (lo + hi) >>> 1;            return (lo >= mid || current != null) ? null :                    new EntrySpliterator<>(map, lo, index = mid, est >>>= 1,                            expectedModCount);        }        public void forEachRemaining(Consumer<? super Map.Entry<K,V>> action) {            int i, hi, mc;            if (action == null)                throw new NullPointerException();            HashMap<K,V> m = map;            Node<K,V>[] tab = m.table;            if ((hi = fence) < 0) {                mc = expectedModCount = m.modCount;                hi = fence = (tab == null) ? 0 : tab.length;            }            else                mc = expectedModCount;            if (tab != null && tab.length >= hi &&                    (i = index) >= 0 && (i < (index = hi) || current != null)) {                Node<K,V> 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.Entry<K,V>> action) {            int hi;            if (action == null)                throw new NullPointerException();            Node<K,V>[] tab = map.table;            if (tab != null && tab.length >= (hi = getFence()) && index >= 0) {                while (current != null || index < hi) {                    if (current == null)                        current = tab[index++];                    else {                        Node<K,V> 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;        }    }    Node<K,V> newNode(int hash, K key, V value, Node<K,V> next) {        return new Node<>(hash, key, value, next);    }    // For conversion from TreeNodes to plain nodes    Node<K,V> replacementNode(Node<K,V> p, Node<K,V> next) {        return new Node<>(p.hash, p.key, p.value, next);    }    // Create a tree bin node    TreeNode<K,V> newTreeNode(int hash, K key, V value, Node<K,V> next) {        return new TreeNode<>(hash, key, value, next);    }    // For treeifyBin    TreeNode<K,V> replacementTreeNode(Node<K,V> p, Node<K,V> next) {        return new TreeNode<>(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(Node<K,V> p) { }    void afterNodeInsertion(boolean evict) { }    void afterNodeRemoval(Node<K,V> p) { }    // Called only from writeObject, to ensure compatible ordering.    void internalWriteEntries(java.io.ObjectOutputStream s) throws IOException {        Node<K,V>[] tab;        if (size > 0 && (tab = table) != null) {            for (int i = 0; i < tab.length; ++i) {                for (Node<K,V> e = tab[i]; e != null; e = e.next) {                    s.writeObject(e.key);                    s.writeObject(e.value);                }            }        }    }    static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {        TreeNode<K,V> parent;  // red-black tree links        TreeNode<K,V> left;        TreeNode<K,V> right;        TreeNode<K,V> prev;    // needed to unlink next upon deletion        boolean red;        TreeNode(int hash, K key, V val, Node<K,V> next) {            super(hash, key, val, next);        }        /**         * Returns root of tree containing this node.         */        final TreeNode<K,V> root() {            for (TreeNode<K,V> 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 <K,V> void moveRootToFront(Node<K,V>[] tab, TreeNode<K,V> root) {            int n;            if (root != null && tab != null && (n = tab.length) > 0) {                int index = (n - 1) & root.hash;                TreeNode<K,V> first = (TreeNode<K,V>)tab[index];                if (root != first) {                    Node<K,V> rn;                    tab[index] = root;                    TreeNode<K,V> rp = root.prev;                    if ((rn = root.next) != null)                        ((TreeNode<K,V>)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 TreeNode<K,V> find(int h, Object k, Class<?> kc) {            TreeNode<K,V> p = this;            do {                int ph, dir; K pk;                TreeNode<K,V> 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 TreeNode<K,V> 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(Node<K,V>[] tab) {            TreeNode<K,V> root = null;            for (TreeNode<K,V> x = this, next; x != null; x = next) {                next = (TreeNode<K,V>)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;                    Class<?> kc = null;                    for (TreeNode<K,V> 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);                        TreeNode<K,V> 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 Node<K,V> untreeify(HashMap<K,V> map) {            Node<K,V> hd = null, tl = null;            for (Node<K,V> q = this; q != null; q = q.next) {                Node<K,V> p = map.replacementNode(q, null);                if (tl == null)                    hd = p;                else                    tl.next = p;                tl = p;            }            return hd;        }        final TreeNode<K,V> putTreeVal(HashMap<K,V> map, Node<K,V>[] tab,                                       int h, K k, V v) {            Class<?> kc = null;            boolean searched = false;            TreeNode<K,V> root = (parent != null) ? root() : this;            for (TreeNode<K,V> 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) {                        TreeNode<K,V> 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);                }                TreeNode<K,V> xp = p;                if ((p = (dir <= 0) ? p.left : p.right) == null) {                    Node<K,V> xpn = xp.next;                    TreeNode<K,V> 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)                        ((TreeNode<K,V>)xpn).prev = x;                    moveRootToFront(tab, balanceInsertion(root, x));                    return null;                }            }        }        final void removeTreeNode(HashMap<K,V> map, Node<K,V>[] tab,                                  boolean movable) {            int n;            if (tab == null || (n = tab.length) == 0)                return;            int index = (n - 1) & hash;            TreeNode<K,V> first = (TreeNode<K,V>)tab[index], root = first, rl;            TreeNode<K,V> succ = (TreeNode<K,V>)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;            }            TreeNode<K,V> p = this, pl = left, pr = right, replacement;            if (pl != null && pr != null) {                TreeNode<K,V> 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                TreeNode<K,V> sr = s.right;                TreeNode<K,V> pp = p.parent;                if (s == pr) { // p was s's direct parent                    p.parent = s;                    s.right = p;                }                else {                    TreeNode<K,V> 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) {                TreeNode<K,V> 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;            }            TreeNode<K,V> r = p.red ? root : balanceDeletion(root, replacement);            if (replacement == p) {  // detach                TreeNode<K,V> 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(HashMap<K,V> map, Node<K,V>[] tab, int index, int bit) {            TreeNode<K,V> b = this;// Relink into lo and hi lists, preserving order            TreeNode<K,V> loHead = null, loTail = null;            TreeNode<K,V> hiHead = null, hiTail = null;            int lc = 0, hc = 0;            for (TreeNode<K,V> e = b, next; e != null; e = next) {                next = (TreeNode<K,V>)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 <K,V> TreeNode<K,V> rotateLeft(TreeNode<K,V> root,                                              TreeNode<K,V> p) {            TreeNode<K,V> 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 <K,V> TreeNode<K,V> rotateRight(TreeNode<K,V> root,                                               TreeNode<K,V> p) {            TreeNode<K,V> 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 <K,V> TreeNode<K,V> balanceInsertion(TreeNode<K,V> root,                                                    TreeNode<K,V> x) {            x.red = true;            for (TreeNode<K,V> 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 <K,V> TreeNode<K,V> balanceDeletion(TreeNode<K,V> root,                                                   TreeNode<K,V> x) {            for (TreeNode<K,V> 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 {                        TreeNode<K,V> 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 {                        TreeNode<K,V> 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 <K,V> boolean checkInvariants(TreeNode<K,V> t) {            TreeNode<K,V> tp = t.parent, tl = t.left, tr = t.right,                    tb = t.prev, tn = (TreeNode<K,V>)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;        }    }}


1 0
原创粉丝点击