0

0

Java集合之WeakHashMap详解

黄舟

黄舟

发布时间:2017-03-13 17:44:25

|

1883人浏览过

|

来源于php中文网

原创

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的关系图:



(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主要的Map0


clear()
Object                 clone()
containsKey(Object key)
containsValue(Object value)
Set<<>>       entrySet()
V                      get(Object key)
isEmpty()
Set<>                 keySet()
V                      put(K keyV value)
putAll(Map map)
V                      remove(Object key)
size()
Collection<>          values()

weakhashmap的遍历方式

(1)遍历WeakHashMap的键值对:首先根据entrySet()获得键值对集合,然后对集合通过迭代器Iterator遍历得到键值。


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

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


String key = Integer integ = Iterator iter = map.keySet().iterator()(iter.hasNext()) {
    key = (String)iter.next()    integ = (Integer)map.get(key)}

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

Snowy(SnowyAdmin)快速开发平台3.5.1
Snowy(SnowyAdmin)快速开发平台3.5.1

Snowy(SnowyAdmin)是国内首个国密前后端分离快速开发平台,集成国密加解密插件, 软件层面完全符合等保测评要求,同时实现国产化机型、中间件、数据库适配,是您的不二之选! 技术框架与密码结合,让更多的人认识密码,使用密码;更是让前后分离“密”不可分。采用SpringBoot+MybatisPlus+AntDesignVue+Vite 等更多组件及前沿技术开发,注释丰富,代码简洁,开箱即用

下载


Integer value = Collection c = map.values()Iterator iter= c.iterator()(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 extends AbstractMap
        implements Map {
    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[] table;
    private int size;//数目
    private int threshold;//阈值
    private final float loadFactor;//加载因子
    private final ReferenceQueue queue = new ReferenceQueue<>();//引用队列
    int modCount;//fail-fast
    @SuppressWarnings("unchecked")
    private Entry[] newTable(int n) {
        return (Entry[]) 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 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 e = (Entry) x;
                int i = indexFor(e.hash, table.length);

                Entry prev = table[i];
                Entry p = prev;
                while (p != null) {
                    Entry 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[] 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 true 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.
     *
     * 

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.) * *

A return value of {@code null} does not necessarily * 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[] tab = getTable(); int index = indexFor(h, tab.length); Entry e = tab[index]; while (e != null) { if (e.hash == h && eq(k, e.get())) return e.value; e = e.next; } return null; } /** * Returns true if this map contains a mapping for the * specified key. * * @param key The key whose presence in this map is to be tested * @return true if there is a mapping for key; * false 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 getEntry(Object key) { Object k = maskNull(key); int h = hash(k); Entry[] tab = getTable(); int index = indexFor(h, tab.length); Entry 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 key, or * null if there was no mapping for key. * (A null return can also indicate that the map * previously associated null with key.) */ //插入key和value public V put(K key, V value) { Object k = maskNull(key); int h = hash(k); Entry[] tab = getTable(); int i = indexFor(h, tab.length); for (Entry 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 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[] oldTable = getTable(); int oldCapacity = oldTable.length; if (oldCapacity == MAXIMUM_CAPACITY) { threshold = Integer.MAX_VALUE; return; } Entry[] 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[] src, Entry[] dest) { for (int j = 0; j < src.length; ++j) { Entry e = src[j]; src[j] = null; while (e != null) { Entry 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 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 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 k to * value v such that (key==null ? k==null : * key.equals(k)), that mapping is removed. (The map can contain * at most one such mapping.) * *

Returns the value to which this map previously associated the key, * or null if the map contained no mapping for the key. A * return value of null does not necessarily indicate * that the map contained no mapping for the key; it's also possible * that the map explicitly mapped the key to null. * *

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 key, or * null if there was no mapping for key */ //根据key删除 public V remove(Object key) { Object k = maskNull(key); int h = hash(k); Entry[] tab = getTable(); int i = indexFor(h, tab.length); Entry prev = tab[i]; Entry e = prev; while (e != null) { Entry 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[] tab = getTable(); Map.Entry entry = (Map.Entry)o; Object k = maskNull(entry.getKey()); int h = hash(k); int i = indexFor(h, tab.length); Entry prev = tab[i]; Entry e = prev; while (e != null) { Entry 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 true 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 true if this map maps one or more keys to the * specified value */ //判断是否包含某个值 public boolean containsValue(Object value) { if (value==null) return containsNullValue(); Entry[] tab = getTable(); for (int i = tab.length; i-- > 0;) for (Entry 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[] tab = getTable(); for (int i = tab.length; i-- > 0;) for (Entry 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 extends WeakReference implements Map.Entry { V value; final int hash; Entry next; /** * Creates new entry. */ Entry(Object key, V value, ReferenceQueue queue, int hash, Entry 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 implements Iterator { private int index; private Entry entry; private Entry 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[] t = table; while (nextKey == null) { Entry 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 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 { public V next() { return nextEntry().value; } } private class KeyIterator extends HashIterator { public K next() { return nextEntry().getKey(); } } private class EntryIterator extends HashIterator> { public Map.Entry next() { return nextEntry(); } } // Views private transient Set> 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 remove operation), the results of * the iteration are undefined. The set supports element removal, * which removes the corresponding mapping from the map, via the * Iterator.remove, Set.remove, * removeAll, retainAll, and clear * operations. It does not support the add or addAll * operations. */ public Set keySet() { Set ks = keySet; return (ks != null ? ks : (keySet = new KeySet())); } private class KeySet extends AbstractSet { public Iterator 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 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 remove operation), * the results of the iteration are undefined. The collection * supports element removal, which removes the corresponding * mapping from the map, via the Iterator.remove, * Collection.remove, removeAll, * retainAll and clear operations. It does not * support the add or addAll operations. */ public Collection values() { Collection vs = values; return (vs != null) ? vs : (values = new Values()); } private class Values extends AbstractCollection { public Iterator 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 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 remove operation, or through the * setValue 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 Iterator.remove, * Set.remove, removeAll, retainAll and * clear operations. It does not support the * add or addAll operations. */ public Set> entrySet() { Set> es = entrySet; return es != null ? es : (entrySet = new EntrySet()); } private class EntrySet extends AbstractSet> { public Iterator> iterator() { return new EntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Entry 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> deepCopy() { List> list = new ArrayList<>(size()); for (Map.Entry e : this) list.add(new AbstractMap.SimpleEntry<>(e)); return list; } public Object[] toArray() { return deepCopy().toArray(); } public T[] toArray(T[] a) { return deepCopy().toArray(a); } public Spliterator> spliterator() { return new EntrySpliterator<>(WeakHashMap.this, 0, -1, 0, 0); } } @SuppressWarnings("unchecked") @Override public void forEach(BiConsumer action) { Objects.requireNonNull(action); int expectedModCount = modCount; Entry[] tab = getTable(); for (Entry 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 function) { Objects.requireNonNull(function); int expectedModCount = modCount; Entry[] tab = getTable();; for (Entry 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 { final WeakHashMap map; WeakHashMap.Entry 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 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 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 extends WeakHashMapSpliterator implements Spliterator { KeySpliterator(WeakHashMap m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public KeySpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : new KeySpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer action) { int i, hi, mc; if (action == null) throw new NullPointerException(); WeakHashMap m = map; WeakHashMap.Entry[] 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 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 action) { int hi; if (action == null) throw new NullPointerException(); WeakHashMap.Entry[] 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 extends WeakHashMapSpliterator implements Spliterator { ValueSpliterator(WeakHashMap m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public ValueSpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : new ValueSpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer action) { int i, hi, mc; if (action == null) throw new NullPointerException(); WeakHashMap m = map; WeakHashMap.Entry[] 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 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 action) { int hi; if (action == null) throw new NullPointerException(); WeakHashMap.Entry[] 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 extends WeakHashMapSpliterator implements Spliterator> { EntrySpliterator(WeakHashMap m, int origin, int fence, int est, int expectedModCount) { super(m, origin, fence, est, expectedModCount); } public EntrySpliterator trySplit() { int hi = getFence(), lo = index, mid = (lo + hi) >>> 1; return (lo >= mid) ? null : new EntrySpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer> action) { int i, hi, mc; if (action == null) throw new NullPointerException(); WeakHashMap m = map; WeakHashMap.Entry[] 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 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)); } } } while (p != null || i < hi); } if (m.modCount != mc) throw new ConcurrentModificationException(); } public boolean tryAdvance(Consumer> action) { int hi; if (action == null) throw new NullPointerException(); WeakHashMap.Entry[] 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)); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } } } return false; } public int characteristics() { return Spliterator.DISTINCT; } } }

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
c++主流开发框架汇总
c++主流开发框架汇总

本专题整合了c++开发框架推荐,阅读专题下面的文章了解更多详细内容。

79

2026.01.09

c++框架学习教程汇总
c++框架学习教程汇总

本专题整合了c++框架学习教程汇总,阅读专题下面的文章了解更多详细内容。

46

2026.01.09

学python好用的网站推荐
学python好用的网站推荐

本专题整合了python学习教程汇总,阅读专题下面的文章了解更多详细内容。

121

2026.01.09

学python网站汇总
学python网站汇总

本专题整合了学python网站汇总,阅读专题下面的文章了解更多详细内容。

12

2026.01.09

python学习网站
python学习网站

本专题整合了python学习相关推荐汇总,阅读专题下面的文章了解更多详细内容。

15

2026.01.09

俄罗斯手机浏览器地址汇总
俄罗斯手机浏览器地址汇总

汇总俄罗斯Yandex手机浏览器官方网址入口,涵盖国际版与俄语版,适配移动端访问,一键直达搜索、地图、新闻等核心服务。

71

2026.01.09

漫蛙稳定版地址大全
漫蛙稳定版地址大全

漫蛙稳定版地址大全汇总最新可用入口,包含漫蛙manwa漫画防走失官网链接,确保用户随时畅读海量正版漫画资源,建议收藏备用,避免因域名变动无法访问。

370

2026.01.09

php学习网站大全
php学习网站大全

精选多个优质PHP入门学习网站,涵盖教程、实战与文档,适合零基础到进阶开发者,助你高效掌握PHP编程。

45

2026.01.09

php网站搭建教程大全
php网站搭建教程大全

本合集专为零基础用户打造,涵盖PHP网站搭建全流程,从环境配置到实战开发,免费、易懂、系统化,助你快速入门建站!

12

2026.01.09

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.4万人学习

C# 教程
C# 教程

共94课时 | 6.5万人学习

Java 教程
Java 教程

共578课时 | 44.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号