Java集合之WeakHashMap[通俗易懂]

Java集合之WeakHashMap[通俗易懂]WeakHashMap继承于AbstractMap,同时实现了Map接口。和HashMap一样,WeakHashMap也是一个散列表,存储的内容也是键值对key-value映射,并且键和值都可以是null。WeakHashMap的键都是弱键,给定一个键,其映射的存在并不阻止垃圾回收器对该键的丢弃,使该键成为可终止,然后被回收。弱键的原理就是Entry继承了WeakReference接口,当G

大家好,又见面了,我是你们的朋友全栈君。

WeakHashMap继承于AbstractMap,同时实现了Map接口。
和HashMap一样,WeakHashMap也是一个散列表,存储的内容也是键值对 key-value映射,并且键和值都可以是null。WeakHashMap的键都是弱键,给定一个键,其映射的存在并不阻止垃圾回收器对该键的丢弃,使该键成为可终止,然后被回收。弱键的原理就是Entry继承了WeakReference接口,当GC 回收时,”弱键“同时也会被添加到ReferenceQueue队列中。
实现的步骤:
(1)新建WeakHashMap,将键值对添加到WeakHashMap中,WeakHashMap同样也是通过table保存Entry(键值对),每一个Entry实际上是一个单向链表。
(2)当某个弱键不再被其他对象引用,并被GC回收时,在GC回收该弱键时,这个弱键也同时会被添加到ReferenceQueue(queue)队列中。
(3)下一次需要操作WeakHashMap时,会先同步table和queue。table中保存了全部的键值对,而queue中保存被GC回收的键值对,同时会删除table中被GC回收的键值对。WeakHashMap也不是线程安全的。
WeakHashMap的关系图:
Java集合之WeakHashMap[通俗易懂]

(1)WeakHashMap继承于AbstractMap,并且实现了Map接口。
(2)WeakHashMap是哈希表,它的键时弱键,WeakHashMap同样有几个重要的成员变量:table,size,threshold,loadFactor,modCount,queue。
table一个Entry[]数组类型,而每个Entry实际上就是一个单向链表,哈希表的key-value键值对都是存储在Entry数组中的。
size是Hashtable的大小,它是Hashtable保存的键值对的数量。
threshold是Hashtable的阈值,用于判断是否需要调整Hashtable的容量。threshold的值=”容量*加载因子“
loadFactor加载因子
modCount是用来实现fail-fast机制
queue保存的是已经被GC清楚的弱引用的键。

WeakHashMap主要的函数
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()

WeakHashMap的遍历方式

(1)遍历WeakHashMap的键值对:首先根据entrySet()获得键值对集合,然后对集合通过迭代器Iterator遍历得到键值。
Integer integ = null;
Iterator iter = map.entrySet().iterator();
while(iter.hasNext())
{
Map.Entry entry = (Map.Entry)iter.next();
// 获取key
key = (String)entry.getKey();
// 获取value
integ = (Integer)entry.getValue();
}

(2)遍历WeakHashMap的键:首先通过keySet()获取WeakHashMap的键的set集合,通过Iterator迭代器遍历集合来获得键值。

String key = null;
Integer integ = null;
Iterator iter = map.keySet().iterator();
while (iter.hasNext()) {
// 获取key
key = (String)iter.next();
// 根据key,获取value
integ = (Integer)map.get(key);
}

(3)遍历WeakHashMap的值:首先通过values()获取WeakHashMap的value集合,然后对集合进行迭代获得数据。

Integer value = null;
Collection c = map.values();
Iterator iter= c.iterator();
while (iter.hasNext())
{
value = (Integer)iter.next();
}

WeakHashMap示例程序:

public class Hello {

    public static void main(String[] args) throws Exception {
        testWeakHashMapAPIs();
    }

    private static void testWeakHashMapAPIs()
    {
        // 初始化3个“弱键”
        String w1 = new String("one");
        String w2 = new String("two");
        String w3 = new String("three");
        // 新建WeakHashMap
        Map wmap = new WeakHashMap();
        // 添加键值对
        wmap.put(w1, "w1");
        wmap.put(w2, "w2");
        wmap.put(w3, "w3");

        // 打印出wmap
        System.out.printf("\nwmap:%s\n",wmap );

        // containsKey(Object key) :是否包含键key
        System.out.printf("contains key two : %s\n",wmap.containsKey("two"));
        System.out.printf("contains key five : %s\n",wmap.containsKey("five"));
        // containsValue(Object value) :是否包含值value
        System.out.printf("contains value 0 : %s\n",wmap.containsValue(new Integer(0)));
        // remove(Object key) : 删除键key对应的键值对
        wmap.remove("three");
        System.out.printf("wmap: %s\n",wmap );
        // ---- 测试 WeakHashMap 的自动回收特性 ----
        // 将w1设置null。
        // 这意味着“弱键”w1再没有被其它对象引用,调用gc时会回收WeakHashMap中与“w1”对应的键值对
        w1 = null;
        // 内存回收。这里,会回收WeakHashMap中与“w1”对应的键值对
        System.gc();
        // 遍历WeakHashMap
        Iterator iter = wmap.entrySet().iterator();
        while (iter.hasNext())
        {
            Map.Entry en = (Map.Entry)iter.next();
            System.out.printf("next : %s - %s\n",en.getKey(),en.getValue());
        }
        // 打印WeakHashMap的实际大小
        System.out.printf(" after gc WeakHashMap size:%s\n", wmap.size());
    }

}

运行结果:
wmap:{three=w3, one=w1, two=w2}
contains key two : true
contains key five : false
contains value 0 : false
wmap: {one=w1, two=w2}
next : two – w2
 after gc WeakHashMap size:1

基于Java8的WeakHashMap源代码:

public class WeakHashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V> {
    private static final int DEFAULT_INITIAL_CAPACITY = 16;//默认初始大小,必须是2的次幂
    private static final int MAXIMUM_CAPACITY = 1 << 30;//最大值2的30次方
    private static final float DEFAULT_LOAD_FACTOR = 0.75f;//加载因子
    Entry<K,V>[] table;
    private int size;//数目
    private int threshold;//阈值
    private final float loadFactor;//加载因子
    private final ReferenceQueue<Object> queue = new ReferenceQueue<>();//引用队列
    int modCount;//fail-fast
    @SuppressWarnings("unchecked")
    private Entry<K,V>[] newTable(int n) {
        return (Entry<K,V>[]) new Entry<?,?>[n];
    }
    //构造函数
    public WeakHashMap(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);
        int capacity = 1;
        while (capacity < initialCapacity)
            capacity <<= 1;
        table = newTable(capacity);
        this.loadFactor = loadFactor;
        threshold = (int)(capacity * loadFactor);
    }
    //初始值的构造函数
    public WeakHashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
    //构造函数
    public WeakHashMap() {
        this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
    }
    public WeakHashMap(Map<? extends K, ? extends V> m) {
        this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1,
                        DEFAULT_INITIAL_CAPACITY),
                DEFAULT_LOAD_FACTOR);
        putAll(m);
    }

    // internal utilities

    /**  * Value representing null keys inside tables.  */  private static final Object NULL_KEY = new Object();

    /**  * Use NULL_KEY for key if it is null.  */  private static Object maskNull(Object key) {
        return (key == null) ? NULL_KEY : key;
    }

    /**  * Returns internal representation of null key back to caller as null.  */  static Object unmaskNull(Object key) {
        return (key == NULL_KEY) ? null : key;
    }

    /**  * Checks for equality of non-null reference x and possibly-null y. By  * default uses Object.equals.  */  private static boolean eq(Object x, Object y) {
        return x == y || x.equals(y);
    }

    /**  * Retrieve object hash code and applies a supplemental hash function to the  * result hash, which defends against poor quality hash functions. This is  * critical because HashMap uses power-of-two length hash tables, that  * otherwise encounter collisions for hashCodes that do not differ  * in lower bits.  */  //计算k的hash
    final int hash(Object k) {
        int h = k.hashCode();

        // This function ensures that hashCodes that differ only by
        // constant multiples at each bit position have a bounded
        // number of collisions (approximately 8 at default load factor).
        h ^= (h >>> 20) ^ (h >>> 12);
        return h ^ (h >>> 7) ^ (h >>> 4);
    }

    /**  * Returns index for hash code h.  */  private static int indexFor(int h, int length) {
        return h & (length-1);
    }

    /**  * Expunges stale entries from the table.  */  private void expungeStaleEntries() {
        for (Object x; (x = queue.poll()) != null; ) {
            synchronized (queue) {
                @SuppressWarnings("unchecked")
                Entry<K,V> e = (Entry<K,V>) x;
                int i = indexFor(e.hash, table.length);

                Entry<K,V> prev = table[i];
                Entry<K,V> p = prev;
                while (p != null) {
                    Entry<K,V> next = p.next;
                    if (p == e) {
                        if (prev == e)
                            table[i] = next;
                        else
                            prev.next = next;
                        // Must not null out e.next;
                        // stale entries may be in use by a HashIterator
                        e.value = null; // Help GC
                        size--;
                        break;
                    }
                    prev = p;
                    p = next;
                }
            }
        }
    }

    /**  * Returns the table after first expunging stale entries.  */  private Entry<K,V>[] getTable() {
        expungeStaleEntries();
        return table;
    }

    /**  * Returns the number of key-value mappings in this map.  * This result is a snapshot, and may not reflect unprocessed  * entries that will be removed before next attempted access  * because they are no longer referenced.  */  //返回数目
    public int size() {
        if (size == 0)
            return 0;
        expungeStaleEntries();
        return size;
    }

    /**  * Returns <tt>true</tt> if this map contains no key-value mappings.  * This result is a snapshot, and may not reflect unprocessed  * entries that will be removed before next attempted access  * because they are no longer referenced.  */  //判断是否为空
    public boolean isEmpty() {
        return size() == 0;
    }

    /**  * Returns the value to which the specified key is mapped,  * or { 
    @code null} if this map contains no mapping for the key.  *  * <p>More formally, if this map contains a mapping from a key  * { 
    @code k} to a value { 
    @code v} such that { 
    @code (key==null ? k==null :  * key.equals(k))}, then this method returns { 
    @code v}; otherwise  * it returns { 
    @code null}. (There can be at most one such mapping.)  *  * <p>A return value of { 
    @code null} does not <i>necessarily</i>  * indicate that the map contains no mapping for the key; it's also  * possible that the map explicitly maps the key to { 
    @code null}.  * The { 
    @link #containsKey containsKey} operation may be used to  * distinguish these two cases.  *  * @see #put(Object, Object)  */  //通过key获得value
    public V get(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null) {
            if (e.hash == h && eq(k, e.get()))
                return e.value;
            e = e.next;
        }
        return null;
    }

    /**  * Returns <tt>true</tt> if this map contains a mapping for the  * specified key.  *  * @param key The key whose presence in this map is to be tested  * @return <tt>true</tt> if there is a mapping for <tt>key</tt>;  * <tt>false</tt> otherwise  */  //判断是否包含某个key
    public boolean containsKey(Object key) {
        return getEntry(key) != null;
    }

    /**  * Returns the entry associated with the specified key in this map.  * Returns null if the map contains no mapping for this key.  */  //通过key获得entry
    Entry<K,V> getEntry(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int index = indexFor(h, tab.length);
        Entry<K,V> e = tab[index];
        while (e != null && !(e.hash == h && eq(k, e.get())))
            e = e.next;
        return e;
    }

    /**  * Associates the specified value with the specified key in this map.  * If the map previously contained a mapping for this key, the old  * value is replaced.  *  * @param key key with which the specified value is to be associated.  * @param value value to be associated with the specified key.  * @return the previous value associated with <tt>key</tt>, or  * <tt>null</tt> if there was no mapping for <tt>key</tt>.  * (A <tt>null</tt> return can also indicate that the map  * previously associated <tt>null</tt> with <tt>key</tt>.)  */  //插入key和value
    public V put(K key, V value) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int i = indexFor(h, tab.length);

        for (Entry<K,V> e = tab[i]; e != null; e = e.next) {
            if (h == e.hash && eq(k, e.get())) {
                V oldValue = e.value;
                if (value != oldValue)
                    e.value = value;
                return oldValue;
            }
        }

        modCount++;
        Entry<K,V> e = tab[i];
        tab[i] = new Entry<>(k, value, queue, h, e);
        if (++size >= threshold)
            resize(tab.length * 2);
        return null;
    }

    /**  * Rehashes the contents of this map into a new array with a  * larger capacity. This method is called automatically when the  * number of keys in this map reaches its threshold.  *  * If current capacity is MAXIMUM_CAPACITY, this method does not  * resize the map, but sets threshold to Integer.MAX_VALUE.  * This has the effect of preventing future calls.  *  * @param newCapacity the new capacity, MUST be a power of two;  * must be greater than current capacity unless current  * capacity is MAXIMUM_CAPACITY (in which case value  * is irrelevant).  */  //跳转大小
    void resize(int newCapacity) {
        Entry<K,V>[] oldTable = getTable();
        int oldCapacity = oldTable.length;
        if (oldCapacity == MAXIMUM_CAPACITY) {
            threshold = Integer.MAX_VALUE;
            return;
        }

        Entry<K,V>[] newTable = newTable(newCapacity);
        transfer(oldTable, newTable);
        table = newTable;

        /*
         * If ignoring null elements and processing ref queue caused massive
         * shrinkage, then restore old table.  This should be rare, but avoids
         * unbounded expansion of garbage-filled tables.
         */
        if (size >= threshold / 2) {
            threshold = (int)(newCapacity * loadFactor);
        } else {
            expungeStaleEntries();
            transfer(newTable, oldTable);
            table = oldTable;
        }
    }

    /** Transfers all entries from src to dest tables */  private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
        for (int j = 0; j < src.length; ++j) {
            Entry<K,V> e = src[j];
            src[j] = null;
            while (e != null) {
                Entry<K,V> next = e.next;
                Object key = e.get();
                if (key == null) {
                    e.next = null;  // Help GC
                    e.value = null; //  "   "
                    size--;
                } else {
                    int i = indexFor(e.hash, dest.length);
                    e.next = dest[i];
                    dest[i] = e;
                }
                e = next;
            }
        }
    }

    /**  * Copies all of the mappings from the specified map to this map.  * These mappings will replace any mappings that this map had for any  * of the keys currently in the specified map.  *  * @param m mappings to be stored in this map.  * @throws NullPointerException if the specified map is null.  */  public void putAll(Map<? extends K, ? extends V> m) {
        int numKeysToBeAdded = m.size();
        if (numKeysToBeAdded == 0)
            return;

        /*
         * Expand the map if the map if the number of mappings to be added
         * is greater than or equal to threshold.  This is conservative; the
         * obvious condition is (m.size() + size) >= threshold, but this
         * condition could result in a map with twice the appropriate capacity,
         * if the keys to be added overlap with the keys already in this map.
         * By using the conservative calculation, we subject ourself
         * to at most one extra resize.
         */
        if (numKeysToBeAdded > threshold) {
            int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1);
            if (targetCapacity > MAXIMUM_CAPACITY)
                targetCapacity = MAXIMUM_CAPACITY;
            int newCapacity = table.length;
            while (newCapacity < targetCapacity)
                newCapacity <<= 1;
            if (newCapacity > table.length)
                resize(newCapacity);
        }

        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }

    /**  * Removes the mapping for a key from this weak hash map if it is present.  * More formally, if this map contains a mapping from key <tt>k</tt> to  * value <tt>v</tt> such that <code>(key==null ? k==null :  * key.equals(k))</code>, that mapping is removed. (The map can contain  * at most one such mapping.)  *  * <p>Returns the value to which this map previously associated the key,  * or <tt>null</tt> if the map contained no mapping for the key. A  * return value of <tt>null</tt> does not <i>necessarily</i> indicate  * that the map contained no mapping for the key; it's also possible  * that the map explicitly mapped the key to <tt>null</tt>.  *  * <p>The map will not contain a mapping for the specified key once the  * call returns.  *  * @param key key whose mapping is to be removed from the map  * @return the previous value associated with <tt>key</tt>, or  * <tt>null</tt> if there was no mapping for <tt>key</tt>  */  //根据key删除
    public V remove(Object key) {
        Object k = maskNull(key);
        int h = hash(k);
        Entry<K,V>[] tab = getTable();
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && eq(k, e.get())) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return e.value;
            }
            prev = e;
            e = next;
        }

        return null;
    }

    /** Special version of remove needed by Entry set */  boolean removeMapping(Object o) {
        if (!(o instanceof Map.Entry))
            return false;
        Entry<K,V>[] tab = getTable();
        Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
        Object k = maskNull(entry.getKey());
        int h = hash(k);
        int i = indexFor(h, tab.length);
        Entry<K,V> prev = tab[i];
        Entry<K,V> e = prev;

        while (e != null) {
            Entry<K,V> next = e.next;
            if (h == e.hash && e.equals(entry)) {
                modCount++;
                size--;
                if (prev == e)
                    tab[i] = next;
                else
                    prev.next = next;
                return true;
            }
            prev = e;
            e = next;
        }

        return false;
    }

    /**  * Removes all of the mappings from this map.  * The map will be empty after this call returns.  */  //清空
    public void clear() {
        // clear out ref queue. We don't need to expunge entries
        // since table is getting cleared.
        while (queue.poll() != null)
            ;

        modCount++;
        Arrays.fill(table, null);
        size = 0;

        // Allocation of array may have caused GC, which may have caused
        // additional entries to go stale.  Removing these entries from the
        // reference queue will make them eligible for reclamation.
        while (queue.poll() != null)
            ;
    }

    /**  * Returns <tt>true</tt> if this map maps one or more keys to the  * specified value.  *  * @param value value whose presence in this map is to be tested  * @return <tt>true</tt> if this map maps one or more keys to the  * specified value  */  //判断是否包含某个值
    public boolean containsValue(Object value) {
        if (value==null)
            return containsNullValue();

        Entry<K,V>[] tab = getTable();
        for (int i = tab.length; i-- > 0;)
            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
                if (value.equals(e.value))
                    return true;
        return false;
    }

    /**  * Special-case code for containsValue with null argument  */  //判断是否有空值
    private boolean containsNullValue() {
        Entry<K,V>[] tab = getTable();
        for (int i = tab.length; i-- > 0;)
            for (Entry<K,V> e = tab[i]; e != null; e = e.next)
                if (e.value==null)
                    return true;
        return false;
    }

    /**  * The entries in this hash table extend WeakReference, using its main ref  * field as the key.  */  //entry继承了虚引用
    private static class Entry<K,V> extends WeakReference<Object> implements Map.Entry<K,V> {
        V value;
        final int hash;
        Entry<K,V> next;

        /**  * Creates new entry.  */  Entry(Object key, V value,
              ReferenceQueue<Object> queue,
              int hash, Entry<K,V> next) {
            super(key, queue);
            this.value = value;
            this.hash  = hash;
            this.next  = next;
        }

        @SuppressWarnings("unchecked")
        public K getKey() {
            return (K) WeakHashMap.unmaskNull(get());
        }

        public V getValue() {
            return value;
        }

        public V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public boolean equals(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            K k1 = getKey();
            Object k2 = e.getKey();
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {
                V v1 = getValue();
                Object v2 = e.getValue();
                if (v1 == v2 || (v1 != null && v1.equals(v2)))
                    return true;
            }
            return false;
        }

        public int hashCode() {
            K k = getKey();
            V v = getValue();
            return Objects.hashCode(k) ^ Objects.hashCode(v);
        }

        public String toString() {
            return getKey() + "=" + getValue();
        }
    }

    private abstract class HashIterator<T> implements Iterator<T> {
        private int index;
        private Entry<K,V> entry;
        private Entry<K,V> lastReturned;
        private int expectedModCount = modCount;

        /**  * Strong reference needed to avoid disappearance of key  * between hasNext and next  */  private Object nextKey;

        /**  * Strong reference needed to avoid disappearance of key  * between nextEntry() and any use of the entry  */  private Object currentKey;

        HashIterator() {
            index = isEmpty() ? 0 : table.length;
        }

        public boolean hasNext() {
            Entry<K,V>[] t = table;

            while (nextKey == null) {
                Entry<K,V> e = entry;
                int i = index;
                while (e == null && i > 0)
                    e = t[--i];
                entry = e;
                index = i;
                if (e == null) {
                    currentKey = null;
                    return false;
                }
                nextKey = e.get(); // hold on to key in strong ref
                if (nextKey == null)
                    entry = entry.next;
            }
            return true;
        }

        /** The common parts of next() across different types of iterators */  protected Entry<K,V> nextEntry() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            if (nextKey == null && !hasNext())
                throw new NoSuchElementException();

            lastReturned = entry;
            entry = entry.next;
            currentKey = nextKey;
            nextKey = null;
            return lastReturned;
        }

        public void remove() {
            if (lastReturned == null)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            WeakHashMap.this.remove(currentKey);
            expectedModCount = modCount;
            lastReturned = null;
            currentKey = null;
        }

    }

    private class ValueIterator extends HashIterator<V> {
        public V next() {
            return nextEntry().value;
        }
    }

    private class KeyIterator extends HashIterator<K> {
        public K next() {
            return nextEntry().getKey();
        }
    }

    private class EntryIterator extends HashIterator<Map.Entry<K,V>> {
        public Map.Entry<K,V> next() {
            return nextEntry();
        }
    }

// Views

    private transient Set<Map.Entry<K,V>> entrySet;

    /**  * Returns a { 
    @link Set} view of the keys contained in this map.  * The set is backed by the map, so changes to the map are  * reflected in the set, and vice-versa. If the map is modified  * while an iteration over the set is in progress (except through  * the iterator's own <tt>remove</tt> operation), the results of  * the iteration are undefined. The set supports element removal,  * which removes the corresponding mapping from the map, via the  * <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,  * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>  * operations. It does not support the <tt>add</tt> or <tt>addAll</tt>  * operations.  */  public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
    }

    private class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return new KeyIterator();
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public boolean contains(Object o) {
            return containsKey(o);
        }

        public boolean remove(Object o) {
            if (containsKey(o)) {
                WeakHashMap.this.remove(o);
                return true;
            }
            else
                return false;
        }

        public void clear() {
            WeakHashMap.this.clear();
        }

        public Spliterator<K> spliterator() {
            return new KeySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
        }
    }

    /**  * Returns a { 
    @link Collection} view of the values contained in this map.  * The collection is backed by the map, so changes to the map are  * reflected in the collection, and vice-versa. If the map is  * modified while an iteration over the collection is in progress  * (except through the iterator's own <tt>remove</tt> operation),  * the results of the iteration are undefined. The collection  * supports element removal, which removes the corresponding  * mapping from the map, via the <tt>Iterator.remove</tt>,  * <tt>Collection.remove</tt>, <tt>removeAll</tt>,  * <tt>retainAll</tt> and <tt>clear</tt> operations. It does not  * support the <tt>add</tt> or <tt>addAll</tt> operations.  */  public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null) ? vs : (values = new Values());
    }

    private class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return new ValueIterator();
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public boolean contains(Object o) {
            return containsValue(o);
        }

        public void clear() {
            WeakHashMap.this.clear();
        }

        public Spliterator<V> spliterator() {
            return new ValueSpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
        }
    }

    /**  * Returns a { 
    @link Set} view of the mappings contained in this map.  * The set is backed by the map, so changes to the map are  * reflected in the set, and vice-versa. If the map is modified  * while an iteration over the set is in progress (except through  * the iterator's own <tt>remove</tt> operation, or through the  * <tt>setValue</tt> operation on a map entry returned by the  * iterator) the results of the iteration are undefined. The set  * supports element removal, which removes the corresponding  * mapping from the map, via the <tt>Iterator.remove</tt>,  * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and  * <tt>clear</tt> operations. It does not support the  * <tt>add</tt> or <tt>addAll</tt> operations.  */  public Set<Map.Entry<K,V>> entrySet() {
        Set<Map.Entry<K,V>> es = entrySet;
        return es != null ? es : (entrySet = new EntrySet());
    }

    private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return new EntryIterator();
        }

        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<?,?> e = (Map.Entry<?,?>)o;
            Entry<K,V> candidate = getEntry(e.getKey());
            return candidate != null && candidate.equals(e);
        }

        public boolean remove(Object o) {
            return removeMapping(o);
        }

        public int size() {
            return WeakHashMap.this.size();
        }

        public void clear() {
            WeakHashMap.this.clear();
        }

        private List<Map.Entry<K,V>> deepCopy() {
            List<Map.Entry<K,V>> list = new ArrayList<>(size());
            for (Map.Entry<K,V> e : this)
                list.add(new AbstractMap.SimpleEntry<>(e));
            return list;
        }

        public Object[] toArray() {
            return deepCopy().toArray();
        }

        public <T> T[] toArray(T[] a) {
            return deepCopy().toArray(a);
        }

        public Spliterator<Map.Entry<K,V>> spliterator() {
            return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        int expectedModCount = modCount;

        Entry<K, V>[] tab = getTable();
        for (Entry<K, V> entry : tab) {
            while (entry != null) {
                Object key = entry.get();
                if (key != null) {
                    action.accept((K)WeakHashMap.unmaskNull(key), entry.value);
                }
                entry = entry.next;

                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);
        int expectedModCount = modCount;

        Entry<K, V>[] tab = getTable();;
        for (Entry<K, V> entry : tab) {
            while (entry != null) {
                Object key = entry.get();
                if (key != null) {
                    entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
                }
                entry = entry.next;

                if (expectedModCount != modCount) {
                    throw new ConcurrentModificationException();
                }
            }
        }
    }

    /**  * Similar form as other hash Spliterators, but skips dead  * elements.  */  static class WeakHashMapSpliterator<K,V> {
        final WeakHashMap<K,V> map;
        WeakHashMap.Entry<K,V> current; // current node
        int index;             // current index, modified on advance/split
        int fence;             // -1 until first use; then one past last index
        int est;               // size estimate
        int expectedModCount;  // for comodification checks

        WeakHashMapSpliterator(WeakHashMap<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) {
                WeakHashMap<K,V> m = map;
                est = m.size();
                expectedModCount = m.modCount;
                hi = fence = m.table.length;
            }
            return hi;
        }

        public final long estimateSize() {
            getFence(); // force init
            return (long) est;
        }
    }

    static final class KeySpliterator<K,V>
            extends WeakHashMapSpliterator<K,V>
            implements Spliterator<K> {
        KeySpliterator(WeakHashMap<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) ? null :
                    new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
                            expectedModCount);
        }

        public void forEachRemaining(Consumer<? super K> action) {
            int i, hi, mc;
            if (action == null)
                throw new NullPointerException();
            WeakHashMap<K,V> m = map;
            WeakHashMap.Entry<K,V>[] tab = m.table;
            if ((hi = fence) < 0) {
                mc = expectedModCount = m.modCount;
                hi = fence = tab.length;
            }
            else
                mc = expectedModCount;
            if (tab.length >= hi && (i = index) >= 0 &&
                    (i < (index = hi) || current != null)) {
                WeakHashMap.Entry<K,V> p = current;
                current = null; // exhaust
                do {
                    if (p == null)
                        p = tab[i++];
                    else {
                        Object x = p.get();
                        p = p.next;
                        if (x != null) {
                            @SuppressWarnings("unchecked") K k =
                                    (K) WeakHashMap.unmaskNull(x);
                            action.accept(k);
                        }
                    }
                } 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();
            WeakHashMap.Entry<K,V>[] tab = map.table;
            if (tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null)
                        current = tab[index++];
                    else {
                        Object x = current.get();
                        current = current.next;
                        if (x != null) {
                            @SuppressWarnings("unchecked") K k =
                                    (K) WeakHashMap.unmaskNull(x);
                            action.accept(k);
                            if (map.modCount != expectedModCount)
                                throw new ConcurrentModificationException();
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public int characteristics() {
            return Spliterator.DISTINCT;
        }
    }

    static final class ValueSpliterator<K,V>
            extends WeakHashMapSpliterator<K,V>
            implements Spliterator<V> {
        ValueSpliterator(WeakHashMap<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) ? null :
                    new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
                            expectedModCount);
        }

        public void forEachRemaining(Consumer<? super V> action) {
            int i, hi, mc;
            if (action == null)
                throw new NullPointerException();
            WeakHashMap<K,V> m = map;
            WeakHashMap.Entry<K,V>[] tab = m.table;
            if ((hi = fence) < 0) {
                mc = expectedModCount = m.modCount;
                hi = fence = tab.length;
            }
            else
                mc = expectedModCount;
            if (tab.length >= hi && (i = index) >= 0 &&
                    (i < (index = hi) || current != null)) {
                WeakHashMap.Entry<K,V> p = current;
                current = null; // exhaust
                do {
                    if (p == null)
                        p = tab[i++];
                    else {
                        Object x = p.get();
                        V v = p.value;
                        p = p.next;
                        if (x != null)
                            action.accept(v);
                    }
                } 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();
            WeakHashMap.Entry<K,V>[] tab = map.table;
            if (tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null)
                        current = tab[index++];
                    else {
                        Object x = current.get();
                        V v = current.value;
                        current = current.next;
                        if (x != null) {
                            action.accept(v);
                            if (map.modCount != expectedModCount)
                                throw new ConcurrentModificationException();
                            return true;
                        }
                    }
                }
            }
            return false;
        }

        public int characteristics() {
            return 0;
        }
    }

    static final class EntrySpliterator<K,V>
            extends WeakHashMapSpliterator<K,V>
            implements Spliterator<Map.Entry<K,V>> {
        EntrySpliterator(WeakHashMap<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) ? null :
                    new EntrySpliterator<K,V>(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();
            WeakHashMap<K,V> m = map;
            WeakHashMap.Entry<K,V>[] tab = m.table;
            if ((hi = fence) < 0) {
                mc = expectedModCount = m.modCount;
                hi = fence = tab.length;
            }
            else
                mc = expectedModCount;
            if (tab.length >= hi && (i = index) >= 0 &&
                    (i < (index = hi) || current != null)) {
                WeakHashMap.Entry<K,V> p = current;
                current = null; // exhaust
                do {
                    if (p == null)
                        p = tab[i++];
                    else {
                        Object x = p.get();
                        V v = p.value;
                        p = p.next;
                        if (x != null) {
                            @SuppressWarnings("unchecked") K k =
                                    (K) WeakHashMap.unmaskNull(x);
                            action.accept
                                    (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                        }
                    }
                } 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();
            WeakHashMap.Entry<K,V>[] tab = map.table;
            if (tab.length >= (hi = getFence()) && index >= 0) {
                while (current != null || index < hi) {
                    if (current == null)
                        current = tab[index++];
                    else {
                        Object x = current.get();
                        V v = current.value;
                        current = current.next;
                        if (x != null) {
                            @SuppressWarnings("unchecked") K k =
                                    (K) WeakHashMap.unmaskNull(x);
                            action.accept
                                    (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
                            if (map.modCount != expectedModCount)
                                throw new ConcurrentModificationException();
                            return true;
                        }
                    }
                }
            }
            return false;
        }
        public int characteristics() {
            return Spliterator.DISTINCT;
        }
    }

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/138205.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Ztree简介

    Ztree简介介绍 zTree 是利用 JQuery 的核心代码 实现一套能完成大部分常用功能的 Tree 插件 兼容 IE FireFox Chrome 等浏览器 在一个页面内可同时生成多个 Tree 实例 支持 JSON 数据 支持一次性静态生成和 Ajax 异步加载两种方式 支持多种事件响应及反馈 支持 Tree 的节点移动 编辑 删除 支持任意更换皮肤 个性化图

    2025年11月1日
    3
  • mybatis log plugin激活码激活流程[最新免费获取][通俗易懂]

    (mybatis log plugin激活码激活流程)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1STL5S9V8F-eyJsaWNlbnNlSWQi…

    2022年3月27日
    37
  • 2.在Ubuntu中安装 PyCharm的步骤[通俗易懂]

    2.在Ubuntu中安装 PyCharm的步骤[通俗易懂]在Ubuntu下安装PyCharm软件的详细步骤介绍

    2025年6月14日
    4
  • 关于大数据平台,这有一套完整的方法论,你确定不收藏?[通俗易懂]

    关于大数据平台,这有一套完整的方法论,你确定不收藏?[通俗易懂]大数据时代这个词被提出已有10年了吧,越来越多的企业已经完成了大数据平台的搭建。随着移动互联网和物联网的爆发,大数据价值在越来越多的场景中被挖掘,随着大家都在使用欧冠大数据,大数据平台的搭建门槛也越来越低。借助开源的力量,任何有基础研发能力的组织完全可以搭建自己的大数据平台。但是对于没有了解过大数据平台、数据仓库、数据挖掘概念的同学可能还是无法顺利完成搭建,因为你会发现太多的东西,和架构,你不知道如何去选择。今天给大家分享下大数据平台是怎么玩的。架构总览通常大数据平台的架构如上,从.

    2022年6月3日
    33
  • 关于CPLD与FPGA的对比分析

    关于CPLD与FPGA的对比分析1.PLD/FPGA/CPLDPLD(ProgrammableLogicDevice):可编程逻辑器件,数字集成电路半成品,芯片上按照一定的排列方式集成了大量的门和触发器等基本逻辑元件,使用者按照设计要求运用开发工具将这些片内的元件连接起来,此过程称为编程;FPGA:基于查找表技术,要外挂配置用的EEPROM的PLD产品;由逻辑功能块排列为阵列,并由可编程的内部连线连接…

    2022年6月3日
    38
  • HTML5—-响应式(自适应)网页设计

    HTML5—-响应式(自适应)网页设计

    2021年11月7日
    55

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号