IdentityHashMap 源代码

1、简单介绍

IdentityHashMap,并非用哈希链表来实现,底层是用数组的,比如是存储在table[i] = key,table[i+1] = value

默认容量的大小为32,最小的容量为4,最大的容量大小为1<<29,加载因子loadFactor默认为2/3

    /**
     * The initial capacity used by the no-args constructor.
     * MUST be a power of two.  The value 32 corresponds to the
     * (specified) expected maximum size of 21, given a load factor
     * of 2/3.
     */
    //默认容量大小
    private static final int DEFAULT_CAPACITY = 32;

    /**
     * The minimum capacity, used if a lower value is implicitly specified
     * by either of the constructors with arguments.  The value 4 corresponds
     * to an expected maximum size of 2, given a load factor of 2/3.
     * MUST be a power of two.
     */
    //最小容量大小
    private static final int MINIMUM_CAPACITY = 4;

    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<29.
     */
    //最大容量大小
    private static final int MAXIMUM_CAPACITY = 1 << 29;


2、初始化机制

初始化容量为2^n, 2^(n-1) < expectedMaxSize <= 2^n

    /**
     * Returns the appropriate capacity for the specified expected maximum
     * size.  Returns the smallest power of two between MINIMUM_CAPACITY
     * and MAXIMUM_CAPACITY, inclusive, that is greater than
     * (3 * expectedMaxSize)/2, if such a number exists.  Otherwise
     * returns MAXIMUM_CAPACITY.  If (3 * expectedMaxSize)/2 is negative, it
     * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
     */
    private int capacity(int expectedMaxSize) {
        // Compute min capacity for expectedMaxSize given a load factor of 2/3
        //加载因子默认为2/3
        int minCapacity = (3 * expectedMaxSize)/2;

        // Compute the appropriate capacity
        int result;
        if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
            result = MAXIMUM_CAPACITY;
        } else {
            result = MINIMUM_CAPACITY;
            //最后的result为2的n次方,
            while (result < minCapacity)
                result <<= 1;
        }
        return result;
    }

3、扩容机制

扩容为原来的2倍

    /**
     * Resize the table to hold given capacity.
     *
     * @param newCapacity the new capacity, must be a power of two.
     */
    private void resize(int newCapacity) {
        // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
        //因为每个要存储在2个位置中,所以数组需要为容量的2倍
        int newLength = newCapacity * 2;

        Object[] oldTable = table;
        int oldLength = oldTable.length;
        if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
            //最大只能 容量为2^29  数组长度就得为2^30
            if (threshold == MAXIMUM_CAPACITY-1)
                throw new IllegalStateException("Capacity exhausted.");
            threshold = MAXIMUM_CAPACITY-1;  // Gigantic map!
            return;
        }
        if (oldLength >= newLength)
            return;

        Object[] newTable = new Object[newLength];
        //threshold是2/3cap
        threshold = newLength / 3;

        for (int j = 0; j < oldLength; j += 2) {
            Object key = oldTable[j];
            if (key != null) {
                Object value = oldTable[j+1];

                //将oldTable设为null,用于垃圾回收
                oldTable[j] = null;
                oldTable[j+1] = null;
                int i = hash(key, newLength);
                while (newTable[i] != null)
                    i = nextKeyIndex(i, newLength);
                //将值设在新的table中
                newTable[i] = key;
                newTable[i + 1] = value;
            }
        }
        table = newTable;
    }


4、特殊地方

当key为null时,其实不是真的将key设为null,而是替换成NULL_KEY对象

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

    /**
     * Use NULL_KEY for key if it is null.
     */
    //如果为空,则用NULL_KEY
    private static Object maskNull(Object key) {
        return (key == null ? NULL_KEY : key);
    }

    /**
     * Returns internal representation of null key back to caller as null.
     */
    //如果为NULL_KEY,则返回null
    static final Object unmaskNull(Object key) {
        return (key == NULL_KEY ? null : key);
    }

5、解决hash冲突方法

其实就是往后移2位,直到有空的就将键值对放到里面【线性探测器】

    //获取下一个key的下标index
    private static int nextKeyIndex(int i, int len) {
        return (i + 2 < len ? i + 2 : 0);
    }

6、删除情况

删除一个元素时,需要将当初冲突往后移的键值对往前移

 /**
     * Rehash all possibly-colliding entries following a
     * deletion. This preserves the linear-probe
     * collision properties required by get, put, etc.
     *
     * @param d the index of a newly empty deleted slot
     */
    //删除一个键值对后,当初冲突的键值对需要往前移
    private void closeDeletion(int d) {
        // Adapted from Knuth Section 6.4 Algorithm R
        Object[] tab = table;
        int len = tab.length;

        // Look for items to swap into newly vacated slot
        // starting at index immediately following deletion,
        // and continuing until a null slot is seen, indicating
        // the end of a run of possibly-colliding keys.
        Object item;
        //冲突的键值对往前移
        for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
             i = nextKeyIndex(i, len) ) {
            // The following test triggers if the item at slot i (which
            // hashes to be at slot r) should take the spot vacated by d.
            // If so, we swap it in, and then continue with d now at the
            // newly vacated i.  This process will terminate when we hit
            // the null slot at the end of this run.
            // The test is messy because we are using a circular table.
            int r = hash(item, len);
            if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
                tab[d] = item;
                tab[d + 1] = tab[i + 1];
                tab[i] = null;
                tab[i + 1] = null;
                d = i;
            }
        }
    }

7、源代码

/*
 * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.util;

import java.io.*;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;

/**
 * This class implements the Map interface with a hash table, using
 * reference-equality in place of object-equality when comparing keys (and
 * values).  In other words, in an IdentityHashMap, two keys
 * k1 and k2 are considered equal if and only if
 * (k1==k2).  (In normal Map implementations (like
 * HashMap) two keys k1 and k2 are considered equal
 * if and only if (k1==null ? k2==null : k1.equals(k2)).)
 *
 * 

This class is not a general-purpose Map * implementation! While this class implements the Map interface, it * intentionally violates Map's general contract, which mandates the * use of the equals method when comparing objects. This class is * designed for use only in the rare cases wherein reference-equality * semantics are required. * *

A typical use of this class is topology-preserving object graph * transformations, such as serialization or deep-copying. To perform such * a transformation, a program must maintain a "node table" that keeps track * of all the object references that have already been processed. The node * table must not equate distinct objects even if they happen to be equal. * Another typical use of this class is to maintain proxy objects. For * example, a debugging facility might wish to maintain a proxy object for * each object in the program being debugged. * *

This class provides all of the optional map operations, and permits * null values and the null key. This class makes no * guarantees as to the order of the map; in particular, it does not guarantee * that the order will remain constant over time. * *

This class provides constant-time performance for the basic * operations (get and put), assuming the system * identity hash function ({@link System#identityHashCode(Object)}) * disperses elements properly among the buckets. * *

This class has one tuning parameter (which affects performance but not * semantics): expected maximum size. This parameter is the maximum * number of key-value mappings that the map is expected to hold. Internally, * this parameter is used to determine the number of buckets initially * comprising the hash table. The precise relationship between the expected * maximum size and the number of buckets is unspecified. * *

If the size of the map (the number of key-value mappings) sufficiently * exceeds the expected maximum size, the number of buckets is increased * Increasing the number of buckets ("rehashing") may be fairly expensive, so * it pays to create identity hash maps with a sufficiently large expected * maximum size. On the other hand, iteration over collection views requires * time proportional to the number of buckets in the hash table, so it * pays not to set the expected maximum size too high if you are especially * concerned with iteration performance or memory usage. * *

Note that this implementation is not synchronized. * If multiple threads access an identity hash map concurrently, and at * least one of the threads modifies the map structurally, it must * be synchronized externally. (A structural modification is any operation * that adds or deletes one or more mappings; merely changing the value * associated with a key that an instance already contains is not a * structural modification.) This is typically accomplished by * synchronizing on some object that naturally encapsulates the map. * * If no such object exists, the map should be "wrapped" using the * {@link Collections#synchronizedMap Collections.synchronizedMap} * method. This is best done at creation time, to prevent accidental * unsynchronized access to the map:

 *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));
* *

The iterators returned by the iterator method of the * collections returned by all of this class's "collection view * methods" are fail-fast: if the map is structurally modified * at any time after the iterator is created, in any way except * through the iterator's own remove method, the iterator * will throw a {@link ConcurrentModificationException}. Thus, in the * face of concurrent modification, the iterator fails quickly and * cleanly, rather than risking arbitrary, non-deterministic behavior * at an undetermined time in the future. * *

Note that the fail-fast behavior of an iterator cannot be guaranteed * as it is, generally speaking, impossible to make any hard guarantees in the * presence of unsynchronized concurrent modification. Fail-fast iterators * throw ConcurrentModificationException on a best-effort basis. * Therefore, it would be wrong to write a program that depended on this * exception for its correctness: fail-fast iterators should be used only * to detect bugs. * *

Implementation note: This is a simple linear-probe hash table, * as described for example in texts by Sedgewick and Knuth. The array * alternates holding keys and values. (This has better locality for large * tables than does using separate arrays.) For many JRE implementations * and operation mixes, this class will yield better performance than * {@link HashMap} (which uses chaining rather than linear-probing). * *

This class is a member of the * * Java Collections Framework. * * @see System#identityHashCode(Object) * @see Object#hashCode() * @see Collection * @see Map * @see HashMap * @see TreeMap * @author Doug Lea and Josh Bloch * @since 1.4 */ /* 此类利用哈希表实现 Map 接口,比较键(和值)时使用引用相等性代替对象相等性。换句话说,在 IdentityHashMap 中, 当且仅当 (k1==k2) 时,才认为两个键 k1 和 k2 相等(在正常 Map 实现(如 HashMap)中, 当且仅当满足下列条件时才认为两个键 k1 和 k2 相等:(k1==null ? k2==null : e1.equals(e2)))。 此类不是 通用 Map 实现!此类实现 Map 接口时,它有意违反 Map 的常规协定,该协定在比较对象时强制使用 equals 方法。 此类设计仅用于其中需要引用相等性语义的罕见情况。 此类的典型用法是拓扑保留对象图形转换,如序列化或深层复制。要执行这样的转换,程序必须维护用于跟踪所有已处理对象引用的 “节点表”。节点表一定不等于不同对象,即使它们偶然相等也如此。此类的另一种典型用法是维护代理对象。 例如,调试设施可能希望为正在调试程序中的每个对象维护代理对象。 此类提供所有的可选映射操作,并且允许 null 值和 null 键。此类对映射的顺序不提供任何保证; 特别是不保证顺序随时间的推移保持不变。 此类提供基本操作(get 和 put)的稳定性能,假定系统标识了将桶间元素正确分开的哈希函数 (System.identityHashCode(Object))。 此类具有一个调整参数(影响性能但不影响语义):expected maximum size。此参数是希望映射保持的键值映射关系最大数。 在内部,此参数用于确定最初组成哈希表的桶数。未指定所期望的最大数量和桶数之间的确切关系。 如果映射的大小(键值映射关系数)已经超过期望的最大数量,则桶数会增加,增加桶数(“重新哈希”)可能相当昂贵, 因此创建具有足够大的期望最大数量的标识哈希映射更合算。另一方面,对 collection 视图进行迭代所需的时间与哈希表中 的桶数成正比,所以如果特别注重迭代性能或内存使用,则不宜将期望的最大数量设置得过高。 注意,此实现不是同步的。如果多个线程同时访问标识哈希映射,并且其中至少一个线程从结构上修改了该映射,则其必须 保持外部同步(结构上的修改是指添加或删除一个或多个映射关系的操作;仅改变与实例已经包含的键关联的值不是结构上的修改。) 这一般通过对自然封装该映射的对象进行同步操作来完成。如果不存在这样的对象,则应该使用 Collections.synchronizedMap 方法来“包装”该映射。最好在创建时完成这一操作,以防止对映射进行意外的不同步访问,如下所示: Map m = Collections.synchronizedMap(new HashMap(...)); 由所有此类的“collection 视图方法” 所返回的collections的iterator 方法返回的迭代器都是快速失败 的:在迭代器创建之后,如果从结构上对映射进行修改, 除非通过迭代器自身的 remove 或 add 方法,其他任何时间任何方式的修改,迭代器都将抛出 ConcurrentModificationException。因此,面对并发的修改,迭代器很快就会完全失败, 而不冒在将来不确定的时间任意发生不确定行为的风险。 注意,迭代器的快速失败行为不能得到保证,一般来说,存在不同步的并发修改时,不可能作出任何强有力的保证。 快速失败迭代器尽最大努力抛出 ConcurrentModificationException。因此,编写依赖于此异常的程序的方式是错误的, 正确做法是:迭代器的快速失败行为应该仅用于检测程序错误。 实现注意事项:此为简单的线性探头 哈希表,如 Sedgewick 和 Knuth 原文示例中所述。该数组交替保持键和值 (对于大型表来说,它比使用独立组保持键和值更具优势)。对于多数 JRE 实现和混合操作,此类比 HashMap(它使用链 而不使用线性探头)能产生更好的性能 */ public class IdentityHashMap extends AbstractMap implements Map, java.io.Serializable, Cloneable { /** * The initial capacity used by the no-args constructor. * MUST be a power of two. The value 32 corresponds to the * (specified) expected maximum size of 21, given a load factor * of 2/3. */ //默认容量大小 private static final int DEFAULT_CAPACITY = 32; /** * The minimum capacity, used if a lower value is implicitly specified * by either of the constructors with arguments. The value 4 corresponds * to an expected maximum size of 2, given a load factor of 2/3. * MUST be a power of two. */ //最小容量大小 private static final int MINIMUM_CAPACITY = 4; /** * The maximum capacity, used if a higher value is implicitly specified * by either of the constructors with arguments. * MUST be a power of two <= 1<<29. */ //最大容量大小 private static final int MAXIMUM_CAPACITY = 1 << 29; /** * The table, resized as necessary. Length MUST always be a power of two. */ //缓冲 transient Object[] table; // non-private to simplify nested class access /** * The number of key-value mappings contained in this identity hash map. * * @serial */ //大小 int size; /** * The number of modifications, to support fast-fail iterators */ transient int modCount; /** * The next size value at which to resize (capacity * load factor). */ //阀值 private transient int threshold; /** * Value representing null keys inside tables. */ //空的key static final Object NULL_KEY = new Object(); /** * Use NULL_KEY for key if it is null. */ //如果为空,则用NULL_KEY private static Object maskNull(Object key) { return (key == null ? NULL_KEY : key); } /** * Returns internal representation of null key back to caller as null. */ //如果为NULL_KEY,则返回null static final Object unmaskNull(Object key) { return (key == NULL_KEY ? null : key); } /** * Constructs a new, empty identity hash map with a default expected * maximum size (21). */ public IdentityHashMap() { init(DEFAULT_CAPACITY); } /** * Constructs a new, empty map with the specified expected maximum size. * Putting more than the expected number of key-value mappings into * the map may cause the internal data structure to grow, which may be * somewhat time-consuming. * * @param expectedMaxSize the expected maximum size of the map * @throws IllegalArgumentException if expectedMaxSize is negative */ public IdentityHashMap(int expectedMaxSize) { if (expectedMaxSize < 0) throw new IllegalArgumentException("expectedMaxSize is negative: " + expectedMaxSize); init(capacity(expectedMaxSize)); } /** * Returns the appropriate capacity for the specified expected maximum * size. Returns the smallest power of two between MINIMUM_CAPACITY * and MAXIMUM_CAPACITY, inclusive, that is greater than * (3 * expectedMaxSize)/2, if such a number exists. Otherwise * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned. */ private int capacity(int expectedMaxSize) { // Compute min capacity for expectedMaxSize given a load factor of 2/3 //加载因子默认为2/3 int minCapacity = (3 * expectedMaxSize)/2; // Compute the appropriate capacity int result; if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) { result = MAXIMUM_CAPACITY; } else { result = MINIMUM_CAPACITY; //最后的result为2的倍数, while (result < minCapacity) result <<= 1; } return result; } /** * Initializes object to be an empty map with the specified initial * capacity, which is assumed to be a power of two between * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive. */ private void init(int initCapacity) { // assert (initCapacity & -initCapacity) == initCapacity; // power of 2 // assert initCapacity >= MINIMUM_CAPACITY; // assert initCapacity <= MAXIMUM_CAPACITY; threshold = (initCapacity * 2)/3; table = new Object[2 * initCapacity]; } /** * Constructs a new identity hash map containing the keys-value mappings * in the specified map. * * @param m the map whose mappings are to be placed into this map * @throws NullPointerException if the specified map is null */ public IdentityHashMap(Map m) { // Allow for a bit of growth this((int) ((1 + m.size()) * 1.1)); putAll(m); } /** * Returns the number of key-value mappings in this identity hash map. * * @return the number of key-value mappings in this map */ public int size() { return size; } /** * Returns true if this identity hash map contains no key-value * mappings. * * @return true if this identity hash map contains no key-value * mappings */ public boolean isEmpty() { return size == 0; } /** * Returns index for Object x. */ private static int hash(Object x, int length) { int h = System.identityHashCode(x); // Multiply by -127, and left-shift to use least bit as part of hash return ((h << 1) - (h << 8)) & (length - 1); } /** * Circularly traverses table of size len. */ //获取下一个key的下标index private static int nextKeyIndex(int i, int len) { return (i + 2 < len ? i + 2 : 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 == 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 @SuppressWarnings("unchecked") public V get(Object key) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) //获取value return (V) tab[i + 1]; if (item == null) return null; i = nextKeyIndex(i, len); } } /** * Tests whether the specified object reference is a key in this identity * hash map. * * @param key possible key * @return true if the specified object reference is a key * in this map * @see #containsValue(Object) */ //判断是否包含key public boolean containsKey(Object key) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) return true; if (item == null) return false; i = nextKeyIndex(i, len); } } /** * Tests whether the specified object reference is a value in this identity * hash map. * * @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 object reference * @see #containsKey(Object) */ //是否包含值为value的键值对 public boolean containsValue(Object value) { Object[] tab = table; for (int i = 1; i < tab.length; i += 2) //通过遍历tab if (tab[i] == value && tab[i - 1] != null) return true; return false; } /** * Tests if the specified key-value mapping is in the map. * * @param key possible key * @param value possible value * @return true if and only if the specified key-value * mapping is in the map */ //判断是否有该键值对 private boolean containsMapping(Object key, Object value) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) return tab[i + 1] == value; if (item == null) return false; i = nextKeyIndex(i, len); } } /** * Associates the specified value with the specified key in this identity * hash map. If the map previously contained a mapping for the key, the * old value is replaced. * * @param key the key with which the specified value is to be associated * @param value the 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.) * @see Object#equals(Object) * @see #get(Object) * @see #containsKey(Object) */ //添加键值对 public V put(K key, V value) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); Object item; //直到找到不为null的位置 while ( (item = tab[i]) != null) { if (item == k) { @SuppressWarnings("unchecked") V oldValue = (V) tab[i + 1]; tab[i + 1] = value; return oldValue; } i = nextKeyIndex(i, len); } modCount++; //k, value设在相邻的2个位置 tab[i] = k; tab[i + 1] = value; if (++size >= threshold) resize(len); // len == 2 * current capacity. return null; } /** * Resize the table to hold given capacity. * * @param newCapacity the new capacity, must be a power of two. */ private void resize(int newCapacity) { // assert (newCapacity & -newCapacity) == newCapacity; // power of 2 //因为每个要存储在2个位置中,所以数组需要为容量的2倍 int newLength = newCapacity * 2; Object[] oldTable = table; int oldLength = oldTable.length; if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further //最大只能 容量为2^29 数组长度就得为2^30 if (threshold == MAXIMUM_CAPACITY-1) throw new IllegalStateException("Capacity exhausted."); threshold = MAXIMUM_CAPACITY-1; // Gigantic map! return; } if (oldLength >= newLength) return; Object[] newTable = new Object[newLength]; //threshold是2/3cap threshold = newLength / 3; for (int j = 0; j < oldLength; j += 2) { Object key = oldTable[j]; if (key != null) { Object value = oldTable[j+1]; //将oldTable设为null,用于垃圾回收 oldTable[j] = null; oldTable[j+1] = null; int i = hash(key, newLength); while (newTable[i] != null) i = nextKeyIndex(i, newLength); //将值设在新的table中 newTable[i] = key; newTable[i + 1] = value; } } table = newTable; } /** * 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 */ //将m中的键值对复制到本map中 public void putAll(Map m) { int n = m.size(); if (n == 0) return; if (n > threshold) // conservatively pre-expand resize(capacity(n)); //循环put for (Entry e : m.entrySet()) put(e.getKey(), e.getValue()); } /** * Removes the mapping for this key from this map if present. * * @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. * (A null return can also indicate that the map * previously associated null with key.) */ //移除掉键为key的键值对 public V remove(Object key) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) { //找到该键值对 modCount++; size--; @SuppressWarnings("unchecked") V oldValue = (V) tab[i + 1]; //将key和value设为null tab[i + 1] = null; tab[i] = null; closeDeletion(i); return oldValue; } if (item == null) return null; i = nextKeyIndex(i, len); } } /** * Removes the specified key-value mapping from the map if it is present. * * @param key possible key * @param value possible value * @return true if and only if the specified key-value * mapping was in the map */ //删除掉键值对,必须key,value都相等 private boolean removeMapping(Object key, Object value) { Object k = maskNull(key); Object[] tab = table; int len = tab.length; int i = hash(k, len); while (true) { Object item = tab[i]; if (item == k) { if (tab[i + 1] != value) return false; modCount++; size--; tab[i] = null; tab[i + 1] = null; closeDeletion(i); return true; } if (item == null) return false; i = nextKeyIndex(i, len); } } /** * Rehash all possibly-colliding entries following a * deletion. This preserves the linear-probe * collision properties required by get, put, etc. * * @param d the index of a newly empty deleted slot */ //删除一个键值对后,当初冲突的键值对需要往前移 private void closeDeletion(int d) { // Adapted from Knuth Section 6.4 Algorithm R Object[] tab = table; int len = tab.length; // Look for items to swap into newly vacated slot // starting at index immediately following deletion, // and continuing until a null slot is seen, indicating // the end of a run of possibly-colliding keys. Object item; //冲突的键值对往前移 for (int i = nextKeyIndex(d, len); (item = tab[i]) != null; i = nextKeyIndex(i, len) ) { // The following test triggers if the item at slot i (which // hashes to be at slot r) should take the spot vacated by d. // If so, we swap it in, and then continue with d now at the // newly vacated i. This process will terminate when we hit // the null slot at the end of this run. // The test is messy because we are using a circular table. int r = hash(item, len); if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) { tab[d] = item; tab[d + 1] = tab[i + 1]; tab[i] = null; tab[i + 1] = null; d = i; } } } /** * Removes all of the mappings from this map. * The map will be empty after this call returns. */ //遍历、清除 public void clear() { modCount++; Object[] tab = table; for (int i = 0; i < tab.length; i++) tab[i] = null; size = 0; } /** * Compares the specified object with this map for equality. Returns * true if the given object is also a map and the two maps * represent identical object-reference mappings. More formally, this * map is equal to another map m if and only if * this.entrySet().equals(m.entrySet()). * *

Owing to the reference-equality-based semantics of this map it is * possible that the symmetry and transitivity requirements of the * Object.equals contract may be violated if this map is compared * to a normal map. However, the Object.equals contract is * guaranteed to hold among IdentityHashMap instances. * * @param o object to be compared for equality with this map * @return true if the specified object is equal to this map * @see Object#equals(Object) */ public boolean equals(Object o) { if (o == this) { return true; } else if (o instanceof IdentityHashMap) { IdentityHashMap m = (IdentityHashMap) o; //大小不等返回false if (m.size() != size) return false; Object[] tab = m.table; for (int i = 0; i < tab.length; i+=2) { Object k = tab[i]; //需要key、value都相等 if (k != null && !containsMapping(k, tab[i + 1])) return false; } return true; } else if (o instanceof Map) { Map m = (Map)o; return entrySet().equals(m.entrySet()); } else { return false; // o is not a Map } } /** * Returns the hash code value for this map. The hash code of a map is * defined to be the sum of the hash codes of each entry in the map's * entrySet() view. This ensures that m1.equals(m2) * implies that m1.hashCode()==m2.hashCode() for any two * IdentityHashMap instances m1 and m2, as * required by the general contract of {@link Object#hashCode}. * *

Owing to the reference-equality-based semantics of the * Map.Entry instances in the set returned by this map's * entrySet method, it is possible that the contractual * requirement of Object.hashCode mentioned in the previous * paragraph will be violated if one of the two objects being compared is * an IdentityHashMap instance and the other is a normal map. * * @return the hash code value for this map * @see Object#equals(Object) * @see #equals(Object) */ public int hashCode() { int result = 0; Object[] tab = table; //遍历,将所有key和value的hash相加 for (int i = 0; i < tab.length; i +=2) { Object key = tab[i]; if (key != null) { Object k = unmaskNull(key); result += System.identityHashCode(k) ^ System.identityHashCode(tab[i + 1]); } } return result; } /** * Returns a shallow copy of this identity hash map: the keys and values * themselves are not cloned. * * @return a shallow copy of this map */ public Object clone() { try { IdentityHashMap m = (IdentityHashMap) super.clone(); m.entrySet = null; m.table = table.clone(); return m; } catch (CloneNotSupportedException e) { throw new InternalError(e); } } //迭代器 private abstract class IdentityHashMapIterator implements Iterator { //当前的下标 int index = (size != 0 ? 0 : table.length); // current slot. int expectedModCount = modCount; // to support fast-fail //最后返回的键值对的下标 int lastReturnedIndex = -1; // to allow remove() //当下标的位置为null时就设为false boolean indexValid; // To avoid unnecessary next computation //table的引用 Object[] traversalTable = table; // reference to main table or copy //有下一个元素则返回true public boolean hasNext() { Object[] tab = traversalTable; for (int i = index; i < tab.length; i+=2) { Object key = tab[i]; if (key != null) { index = i; return indexValid = true; } } index = tab.length; return false; } //下一个下标 protected int nextIndex() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (!indexValid && !hasNext()) throw new NoSuchElementException(); indexValid = false; lastReturnedIndex = index; index += 2; return lastReturnedIndex; } //移除掉键值对 public void remove() { if (lastReturnedIndex == -1) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); expectedModCount = ++modCount; int deletedSlot = lastReturnedIndex; lastReturnedIndex = -1; // back up index to revisit new contents after deletion index = deletedSlot; indexValid = false; // Removal code proceeds as in closeDeletion except that // it must catch the rare case where an element already // seen is swapped into a vacant slot that will be later // traversed by this iterator. We cannot allow future // next() calls to return it again. The likelihood of // this occurring under 2/3 load factor is very slim, but // when it does happen, we must make a copy of the rest of // the table to use for the rest of the traversal. Since // this can only happen when we are near the end of the table, // even in these rare cases, this is not very expensive in // time or space. Object[] tab = traversalTable; int len = tab.length; int d = deletedSlot; Object key = tab[d]; //相应的键值对设置为null tab[d] = null; // vacate the slot tab[d + 1] = null; // If traversing a copy, remove in real table. // We can skip gap-closure on copy. //如果是本map中的缓冲table的引用,则调用本map中的remove if (tab != IdentityHashMap.this.table) { IdentityHashMap.this.remove(key); expectedModCount = modCount; return; } size--; //需要将冲突时的那些键值对往前移 Object item; for (int i = nextKeyIndex(d, len); (item = tab[i]) != null; i = nextKeyIndex(i, len)) { int r = hash(item, len); // See closeDeletion for explanation of this conditional if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) { // If we are about to swap an already-seen element // into a slot that may later be returned by next(), // then clone the rest of table for use in future // next() calls. It is OK that our copy will have // a gap in the "wrong" place, since it will never // be used for searching anyway. if (i < deletedSlot && d >= deletedSlot && traversalTable == IdentityHashMap.this.table) { //i为d的下一个位置的下标,i已经超过table的容量,在d前面,这时候将剩下的键值对移到前面 int remaining = len - deletedSlot; Object[] newTable = new Object[remaining]; System.arraycopy(tab, deletedSlot, newTable, 0, remaining); traversalTable = newTable; index = 0; } tab[d] = item; tab[d + 1] = tab[i + 1]; tab[i] = null; tab[i + 1] = null; d = i; } } } } //key的迭代器 private class KeyIterator extends IdentityHashMapIterator { @SuppressWarnings("unchecked") public K next() { return (K) unmaskNull(traversalTable[nextIndex()]); } } //value的迭代器 private class ValueIterator extends IdentityHashMapIterator { @SuppressWarnings("unchecked") public V next() { return (V) traversalTable[nextIndex() + 1]; } } //键值对的迭代器 private class EntryIterator extends IdentityHashMapIterator> { //记录上一次return的实体 private Entry lastReturnedEntry = null; public Map.Entry next() { lastReturnedEntry = new Entry(nextIndex()); return lastReturnedEntry; } //移除掉键值对 public void remove() { lastReturnedIndex = ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index); super.remove(); lastReturnedEntry.index = lastReturnedIndex; lastReturnedEntry = null; } //键值对迭代器的实体 private class Entry implements Map.Entry { private int index; private Entry(int index) { this.index = index; } //得到key @SuppressWarnings("unchecked") public K getKey() { checkIndexForEntryUse(); return (K) unmaskNull(traversalTable[index]); } //得到value @SuppressWarnings("unchecked") public V getValue() { checkIndexForEntryUse(); return (V) traversalTable[index+1]; } //设置value @SuppressWarnings("unchecked") public V setValue(V value) { checkIndexForEntryUse(); V oldValue = (V) traversalTable[index+1]; traversalTable[index+1] = value; // if shadowing, force into main table if (traversalTable != IdentityHashMap.this.table) put((K) traversalTable[index], value); return oldValue; } public boolean equals(Object o) { if (index < 0) return super.equals(o); if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; return (e.getKey() == unmaskNull(traversalTable[index]) && e.getValue() == traversalTable[index+1]); } public int hashCode() { if (lastReturnedIndex < 0) return super.hashCode(); return (System.identityHashCode(unmaskNull(traversalTable[index])) ^ System.identityHashCode(traversalTable[index+1])); } public String toString() { if (index < 0) return super.toString(); return (unmaskNull(traversalTable[index]) + "=" + traversalTable[index+1]); } private void checkIndexForEntryUse() { if (index < 0) throw new IllegalStateException("Entry was removed"); } } } // Views /** * This field is initialized to contain an instance of the entry set * view the first time this view is requested. The view is stateless, * so there's no reason to create more than one. */ private transient Set> entrySet = null; /** * Returns an identity-based 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, 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 methods. It does not support the add or * addAll methods. * *

While the object returned by this method implements the * Set interface, it does not obey Set's general * contract. Like its backing map, the set returned by this method * defines element equality as reference-equality rather than * object-equality. This affects the behavior of its contains, * remove, containsAll, equals, and * hashCode methods. * *

The equals method of the returned set returns true * only if the specified object is a set containing exactly the same * object references as the returned set. The symmetry and transitivity * requirements of the Object.equals contract may be violated if * the set returned by this method is compared to a normal set. However, * the Object.equals contract is guaranteed to hold among sets * returned by this method. * *

The hashCode method of the returned set returns the sum of * the identity hashcodes of the elements in the set, rather than * the sum of their hashcodes. This is mandated by the change in the * semantics of the equals method, in order to enforce the * general contract of the Object.hashCode method among sets * returned by this method. * * @return an identity-based set view of the keys contained in this map * @see Object#equals(Object) * @see System#identityHashCode(Object) */ //返回keySet public Set keySet() { Set ks = keySet; if (ks != null) return ks; else return keySet = new KeySet(); } private class KeySet extends AbstractSet { public Iterator iterator() { return new KeyIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsKey(o); } public boolean remove(Object o) { int oldSize = size; IdentityHashMap.this.remove(o); return size != oldSize; } /* * Must revert from AbstractSet's impl to AbstractCollection's, as * the former contains an optimization that results in incorrect * behavior when c is a smaller "normal" (non-identity-based) Set. */ public boolean removeAll(Collection c) { Objects.requireNonNull(c); boolean modified = false; //获取迭代器,当找到的时候就remove for (Iterator i = iterator(); i.hasNext(); ) { if (c.contains(i.next())) { i.remove(); modified = true; } } return modified; } public void clear() { IdentityHashMap.this.clear(); } public int hashCode() { int result = 0; for (K key : this) result += System.identityHashCode(key); return result; } public Object[] toArray() { return toArray(new Object[0]); } @SuppressWarnings("unchecked") public T[] toArray(T[] a) { int expectedModCount = modCount; int size = size(); //创建数组 if (a.length < size) a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); Object[] tab = table; int ti = 0; for (int si = 0; si < tab.length; si += 2) { //设置key Object key; if ((key = tab[si]) != null) { // key present ? // more elements than expected -> concurrent modification from other thread if (ti >= size) { throw new ConcurrentModificationException(); } a[ti++] = (T) unmaskNull(key); // unmask key } } // fewer elements than expected or concurrent modification from other thread detected if (ti < size || expectedModCount != modCount) { throw new ConcurrentModificationException(); } // final null marker as per spec if (ti < a.length) { a[ti] = null; } return a; } public Spliterator spliterator() { return new KeySpliterator<>(IdentityHashMap.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, * 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 methods. It does not * support the add or addAll methods. * *

While the object returned by this method implements the * Collection interface, it does not obey * Collection's general contract. Like its backing map, * the collection returned by this method defines element equality as * reference-equality rather than object-equality. This affects the * behavior of its contains, remove and * containsAll methods. */ //获取存储value的容器 public Collection values() { Collection vs = values; if (vs != null) return vs; else return values = new Values(); } private class Values extends AbstractCollection { public Iterator iterator() { return new ValueIterator(); } public int size() { return size; } public boolean contains(Object o) { return containsValue(o); } public boolean remove(Object o) { for (Iterator i = iterator(); i.hasNext(); ) { if (i.next() == o) { i.remove(); return true; } } return false; } public void clear() { IdentityHashMap.this.clear(); } public Object[] toArray() { return toArray(new Object[0]); } @SuppressWarnings("unchecked") public T[] toArray(T[] a) { int expectedModCount = modCount; int size = size(); if (a.length < size) a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); Object[] tab = table; int ti = 0; for (int si = 0; si < tab.length; si += 2) { //设置value if (tab[si] != null) { // key present ? // more elements than expected -> concurrent modification from other thread if (ti >= size) { throw new ConcurrentModificationException(); } a[ti++] = (T) tab[si+1]; // copy value } } // fewer elements than expected or concurrent modification from other thread detected if (ti < size || expectedModCount != modCount) { throw new ConcurrentModificationException(); } // final null marker as per spec if (ti < a.length) { a[ti] = null; } return a; } public Spliterator spliterator() { return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0); } } /** * Returns a {@link Set} view of the mappings contained in this map. * Each element in the returned set is a reference-equality-based * Map.Entry. 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, * 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 * methods. It does not support the add or * addAll methods. * *

Like the backing map, the Map.Entry objects in the set * returned by this method define key and value equality as * reference-equality rather than object-equality. This affects the * behavior of the equals and hashCode methods of these * Map.Entry objects. A reference-equality based Map.Entry * e is equal to an object o if and only if o is a * Map.Entry and e.getKey()==o.getKey() && * e.getValue()==o.getValue(). To accommodate these equals * semantics, the hashCode method returns * System.identityHashCode(e.getKey()) ^ * System.identityHashCode(e.getValue()). * *

Owing to the reference-equality-based semantics of the * Map.Entry instances in the set returned by this method, * it is possible that the symmetry and transitivity requirements of * the {@link Object#equals(Object)} contract may be violated if any of * the entries in the set is compared to a normal map entry, or if * the set returned by this method is compared to a set of normal map * entries (such as would be returned by a call to this method on a normal * map). However, the Object.equals contract is guaranteed to * hold among identity-based map entries, and among sets of such entries. * * * @return a set view of the identity-mappings contained in this map */ //键值对的Set public Set> entrySet() { Set> es = entrySet; if (es != null) return es; else return 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 entry = (Map.Entry)o; return containsMapping(entry.getKey(), entry.getValue()); } public boolean remove(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry entry = (Map.Entry)o; return removeMapping(entry.getKey(), entry.getValue()); } public int size() { return size; } public void clear() { IdentityHashMap.this.clear(); } /* * Must revert from AbstractSet's impl to AbstractCollection's, as * the former contains an optimization that results in incorrect * behavior when c is a smaller "normal" (non-identity-based) Set. */ public boolean removeAll(Collection c) { Objects.requireNonNull(c); boolean modified = false; for (Iterator> i = iterator(); i.hasNext(); ) { if (c.contains(i.next())) { i.remove(); modified = true; } } return modified; } public Object[] toArray() { return toArray(new Object[0]); } @SuppressWarnings("unchecked") public T[] toArray(T[] a) { int expectedModCount = modCount; int size = size(); if (a.length < size) a = (T[]) Array.newInstance(a.getClass().getComponentType(), size); Object[] tab = table; int ti = 0; for (int si = 0; si < tab.length; si += 2) { //设置key和value Object key; if ((key = tab[si]) != null) { // key present ? // more elements than expected -> concurrent modification from other thread if (ti >= size) { throw new ConcurrentModificationException(); } a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]); } } // fewer elements than expected or concurrent modification from other thread detected if (ti < size || expectedModCount != modCount) { throw new ConcurrentModificationException(); } // final null marker as per spec if (ti < a.length) { a[ti] = null; } return a; } public Spliterator> spliterator() { return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0); } } private static final long serialVersionUID = 8188218128353913216L; /** * Save the state of the IdentityHashMap instance to a stream * (i.e., serialize it). * * @serialData The size of the HashMap (the number of key-value * mappings) (int), followed by the key (Object) and * value (Object) for each key-value mapping represented by the * IdentityHashMap. The key-value mappings are emitted in no * particular order. */ //序列化的writeObject private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { // Write out and any hidden stuff s.defaultWriteObject(); // Write out size (number of Mappings) //先写size s.writeInt(size); // Write out keys and values (alternating) //再接每个key和value Object[] tab = table; for (int i = 0; i < tab.length; i += 2) { Object key = tab[i]; if (key != null) { s.writeObject(unmaskNull(key)); s.writeObject(tab[i + 1]); } } } /** * Reconstitute the IdentityHashMap instance from a stream (i.e., * deserialize it). */ private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException { // Read in any hidden stuff s.defaultReadObject(); // Read in size (number of Mappings) //读取容量 int size = s.readInt(); // Allow for 33% growth (i.e., capacity is >= 2* size()). //初始化map init(capacity((size*4)/3)); // Read the keys and values, and put the mappings in the table for (int i=0; i action) { Objects.requireNonNull(action); int expectedModCount = modCount; Object[] t = table; for (int index = 0; index < t.length; index += 2) { Object k = t[index]; if (k != null) { //将每个键值对的key和value都传到action action.accept((K) unmaskNull(k), (V) t[index + 1]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } } //通过函数计算后替换value @SuppressWarnings("unchecked") @Override public void replaceAll(BiFunction function) { Objects.requireNonNull(function); int expectedModCount = modCount; Object[] t = table; for (int index = 0; index < t.length; index += 2) { Object k = t[index]; if (k != null) { //调用新的函数计算后设置为新的value t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]); } if (modCount != expectedModCount) { throw new ConcurrentModificationException(); } } } /** * Similar form as array-based Spliterators, but skips blank elements, * and guestimates size as decreasing by half per split. */ static class IdentityHashMapSpliterator { final IdentityHashMap map; //下标 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; // initialized when fence set IdentityHashMapSpliterator(IdentityHashMap map, int origin, int fence, int est, int expectedModCount) { this.map = map; 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) { //初始化 est = map.size; expectedModCount = map.modCount; hi = fence = map.table.length; } return hi; } public final long estimateSize() { getFence(); // force init return (long) est; } } static final class KeySpliterator extends IdentityHashMapSpliterator implements Spliterator { KeySpliterator(IdentityHashMap map, int origin, int fence, int est, int expectedModCount) { super(map, origin, fence, est, expectedModCount); } public KeySpliterator trySplit() { //分割长2半 int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1; return (lo >= mid) ? null : new KeySpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } @SuppressWarnings("unchecked") public void forEachRemaining(Consumer action) { if (action == null) throw new NullPointerException(); int i, hi, mc; Object key; IdentityHashMap m; Object[] a; if ((m = map) != null && (a = m.table) != null && (i = index) >= 0 && (index = hi = getFence()) <= a.length) { for (; i < hi; i += 2) { if ((key = a[i]) != null) //将剩余的key传到action action.accept((K)unmaskNull(key)); } if (m.modCount == expectedModCount) return; } throw new ConcurrentModificationException(); } //获取第一个非null的key @SuppressWarnings("unchecked") public boolean tryAdvance(Consumer action) { if (action == null) throw new NullPointerException(); Object[] a = map.table; int hi = getFence(); while (index < hi) { Object key = a[index]; index += 2; if (key != null) { action.accept((K)unmaskNull(key)); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT; } } static final class ValueSpliterator extends IdentityHashMapSpliterator implements Spliterator { ValueSpliterator(IdentityHashMap 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) & ~1; return (lo >= mid) ? null : new ValueSpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer action) { if (action == null) throw new NullPointerException(); int i, hi, mc; IdentityHashMap m; Object[] a; if ((m = map) != null && (a = m.table) != null && (i = index) >= 0 && (index = hi = getFence()) <= a.length) { for (; i < hi; i += 2) { if (a[i] != null) { @SuppressWarnings("unchecked") V v = (V)a[i+1]; action.accept(v); } } if (m.modCount == expectedModCount) return; } throw new ConcurrentModificationException(); } public boolean tryAdvance(Consumer action) { if (action == null) throw new NullPointerException(); Object[] a = map.table; int hi = getFence(); while (index < hi) { Object key = a[index]; @SuppressWarnings("unchecked") V v = (V)a[index+1]; index += 2; if (key != null) { action.accept(v); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? SIZED : 0); } } static final class EntrySpliterator extends IdentityHashMapSpliterator implements Spliterator> { EntrySpliterator(IdentityHashMap 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) & ~1; return (lo >= mid) ? null : new EntrySpliterator(map, lo, index = mid, est >>>= 1, expectedModCount); } public void forEachRemaining(Consumer> action) { if (action == null) throw new NullPointerException(); int i, hi, mc; IdentityHashMap m; Object[] a; if ((m = map) != null && (a = m.table) != null && (i = index) >= 0 && (index = hi = getFence()) <= a.length) { for (; i < hi; i += 2) { Object key = a[i]; if (key != null) { @SuppressWarnings("unchecked") K k = (K)unmaskNull(key); @SuppressWarnings("unchecked") V v = (V)a[i+1]; action.accept (new AbstractMap.SimpleImmutableEntry(k, v)); } } if (m.modCount == expectedModCount) return; } throw new ConcurrentModificationException(); } public boolean tryAdvance(Consumer> action) { if (action == null) throw new NullPointerException(); Object[] a = map.table; int hi = getFence(); while (index < hi) { Object key = a[index]; @SuppressWarnings("unchecked") V v = (V)a[index+1]; index += 2; if (key != null) { @SuppressWarnings("unchecked") K k = (K)unmaskNull(key); action.accept (new AbstractMap.SimpleImmutableEntry(k, v)); if (map.modCount != expectedModCount) throw new ConcurrentModificationException(); return true; } } return false; } public int characteristics() { return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT; } } }



你可能感兴趣的:(Java源代码)