您的位置:首页 > 编程语言

IdentityHashMap 源代码

2015-11-20 09:56 302 查看
1、简单介绍

IdentityHashMap,并非用哈希链表来实现,底层是用数组的,比如<key, value>是存储在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
//因为每个<key, value>要存储在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 <tt>Map</tt> interface with a hash table, using
* reference-equality in place of object-equality when comparing keys (and
* values).  In other words, in an <tt>IdentityHashMap</tt>, two keys
* <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
* <tt>(k1==k2)</tt>.  (In normal <tt>Map</tt> implementations (like
* <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
* if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
*
* <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
* implementation!  While this class implements the <tt>Map</tt> interface, it
* intentionally violates <tt>Map's</tt> general contract, which mandates the
* use of the <tt>equals</tt> method when comparing objects.  This class is
* designed for use only in the rare cases wherein reference-equality
* semantics are required.</b>
*
* <p>A typical use of this class is <i>topology-preserving object graph
* transformations</i>, 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 <i>proxy objects</i>.  For
* example, a debugging facility might wish to maintain a proxy object for
* each object in the program being debugged.
*
* <p>This class provides all of the optional map operations, and permits
* <tt>null</tt> values and the <tt>null</tt> 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.
*
* <p>This class provides constant-time performance for the basic
* operations (<tt>get</tt> and <tt>put</tt>), assuming the system
* identity hash function ({@link System#identityHashCode(Object)})
* disperses elements properly among the buckets.
*
* <p>This class has one tuning parameter (which affects performance but not
* semantics): <i>expected maximum size</i>.  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.
*
* <p>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.
*
* <p><strong>Note that this implementation is not synchronized.</strong>
* If multiple threads access an identity hash map concurrently, and at
* least one of the threads modifies the map structurally, it <i>must</i>
* 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:<pre>
*   Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
*
* <p>The iterators returned by the <tt>iterator</tt> method of the
* collections returned by all of this class's "collection view
* methods" are <i>fail-fast</i>: if the map is structurally modified
* at any time after the iterator is created, in any way except
* through the iterator's own <tt>remove</tt> 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.
*
* <p>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 <tt>ConcurrentModificationException</tt> on a best-effort basis.
* Therefore, it would be wrong to write a program that depended on this
* exception for its correctness: <i>fail-fast iterators should be used only
* to detect bugs.</i>
*
* <p>Implementation note: This is a simple <i>linear-probe</i> 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 <i>chaining</i> rather than linear-probing).
*
* <p>This class is a member of the
* <a href="{@docRoot}/../technotes/guides/collections/index.html">
* Java Collections Framework</a>.
*
* @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<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, 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 <tt>expectedMaxSize</tt> 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<? extends K, ? extends V> 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 <tt>true</tt> if this identity hash map contains no key-value
* mappings.
*
* @return <tt>true</tt> 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.
*
* <p>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.)
*
* <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
@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  <code>true</code> 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 <tt>true</tt> 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  <code>true</code> 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 <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>.)
* @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
//因为每个<key, value>要存储在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<? extends K, ? extends V> m) {
int n = m.size();
if (n == 0)
return;
if (n > threshold) // conservatively pre-expand
resize(capacity(n));

//循环put
for (Entry<? extends K, ? extends V> 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 <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的键值对
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  <code>true</code> 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
* <tt>true</tt> 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 <tt>m</tt> if and only if
* <tt>this.entrySet().equals(m.entrySet())</tt>.
*
* <p><b>Owing to the reference-equality-based semantics of this map it is
* possible that the symmetry and transitivity requirements of the
* <tt>Object.equals</tt> contract may be violated if this map is compared
* to a normal map.  However, the <tt>Object.equals</tt> contract is
* guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
*
* @param  o object to be compared for equality with this map
* @return <tt>true</tt> 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
* <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
* implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
* <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
* required by the general contract of {@link Object#hashCode}.
*
* <p><b>Owing to the reference-equality-based semantics of the
* <tt>Map.Entry</tt> instances in the set returned by this map's
* <tt>entrySet</tt> method, it is possible that the contractual
* requirement of <tt>Object.hashCode</tt> mentioned in the previous
* paragraph will be violated if one of the two objects being compared is
* an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
*
* @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<T> implements Iterator<T> {
//当前的下标
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<K> {
@SuppressWarnings("unchecked")
public K next() {
return (K) unmaskNull(traversalTable[nextIndex()]);
}
}

//value的迭代器
private class ValueIterator extends IdentityHashMapIterator<V> {
@SuppressWarnings("unchecked")
public V next() {
return (V) traversalTable[nextIndex() + 1];
}
}

//键值对的迭代器
private class EntryIterator
extends IdentityHashMapIterator<Map.Entry<K,V>>
{
//记录上一次return的实体
private Entry lastReturnedEntry = null;

public Map.Entry<K,V> 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<K,V> {
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<Map.Entry<K,V>> 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 <tt>Iterator.remove</tt>,
* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
* <tt>clear</tt> methods.  It does not support the <tt>add</tt> or
* <tt>addAll</tt> methods.
*
* <p><b>While the object returned by this method implements the
* <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> 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 <tt>contains</tt>,
* <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
* <tt>hashCode</tt> methods.</b>
*
* <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
* 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 <tt>Object.equals</tt> contract may be violated if
* the set returned by this method is compared to a normal set.  However,
* the <tt>Object.equals</tt> contract is guaranteed to hold among sets
* returned by this method.</b>
*
* <p>The <tt>hashCode</tt> method of the returned set returns the sum of
* the <i>identity hashcodes</i> of the elements in the set, rather than
* the sum of their hashcodes.  This is mandated by the change in the
* semantics of the <tt>equals</tt> method, in order to enforce the
* general contract of the <tt>Object.hashCode</tt> 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<K> keySet() {
Set<K> ks = keySet;
if (ks != null)
return ks;
else
return keySet = new KeySet();
}

private class KeySet extends AbstractSet<K> {
public Iterator<K> 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<K> 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> 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<K> 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 <tt>Iterator.remove</tt>,
* <tt>Collection.remove</tt>, <tt>removeAll</tt>,
* <tt>retainAll</tt> and <tt>clear</tt> methods.  It does not
* support the <tt>add</tt> or <tt>addAll</tt> methods.
*
* <p><b>While the object returned by this method implements the
* <tt>Collection</tt> interface, it does <i>not</i> obey
* <tt>Collection's</tt> 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 <tt>contains</tt>, <tt>remove</tt> and
* <tt>containsAll</tt> methods.</b>
*/
//获取存储value的容器
public Collection<V> values() {
Collection<V> vs = values;
if (vs != null)
return vs;
else
return values = new Values();
}

private class Values extends AbstractCollection<V> {
public Iterator<V> iterator() {
return new ValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public boolean remove(Object o) {
for (Iterator<V> 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> 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<V> 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
* <tt>Map.Entry</tt>.  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 <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
* <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
* methods.  It does not support the <tt>add</tt> or
* <tt>addAll</tt> methods.
*
* <p>Like the backing map, the <tt>Map.Entry</tt> 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 <tt>equals</tt> and <tt>hashCode</tt> methods of these
* <tt>Map.Entry</tt> objects.  A reference-equality based <tt>Map.Entry
* e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
* <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &&
* e.getValue()==o.getValue()</tt>.  To accommodate these equals
* semantics, the <tt>hashCode</tt> method returns
* <tt>System.identityHashCode(e.getKey()) ^
* System.identityHashCode(e.getValue())</tt>.
*
* <p><b>Owing to the reference-equality-based semantics of the
* <tt>Map.Entry</tt> 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 <tt>Object.equals</tt> contract is guaranteed to
* hold among identity-based map entries, and among sets of such entries.
* </b>
*
* @return a set view of the identity-mappings contained in this map
*/
//键值对的Set
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es = entrySet;
if (es != null)
return es;
else
return 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<?,?> 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<Map.Entry<K,V>> 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> 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<Map.Entry<K,V>> spliterator() {
return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
}
}

private static final long serialVersionUID = 8188218128353913216L;

/**
* Save the state of the <tt>IdentityHashMap</tt> instance to a stream
* (i.e., serialize it).
*
* @serialData The <i>size</i> of the HashMap (the number of key-value
*          mappings) (<tt>int</tt>), 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 <tt>IdentityHashMap</tt> 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<size; i++) {
@SuppressWarnings("unchecked")
K key = (K) s.readObject();
@SuppressWarnings("unchecked")
V value = (V) s.readObject();
putForCreate(key, value);
}
}

/**
* The put method for readObject.  It does not resize the table,
* update modCount, etc.
*/
//序列化readObject时,初始化时初始每个键值对
private void putForCreate(K key, V value)
throws IOException
{
Object k = maskNull(key);
Object[] tab = table;
int len = tab.length;
int i = hash(k, len);

Object item;
while ( (item = tab[i]) != null) {
if (item == k)
throw new java.io.StreamCorruptedException();
i = nextKeyIndex(i, len);
}
tab[i] = k;
tab[i + 1] = value;
}

//遍历每个键值对
@SuppressWarnings("unchecked")
@Override
public void forEach(BiConsumer<? super K, ? super V> 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<? super K, ? super V, ? extends V> 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<K,V> {
final IdentityHashMap<K,V> 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<K,V> 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<K,V>
extends IdentityHashMapSpliterator<K,V>
implements Spliterator<K> {
KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
int expectedModCount) {
super(map, origin, fence, est, expectedModCount);
}

public KeySpliterator<K,V> trySplit() {
//分割长2半
int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
return (lo >= mid) ? null :
new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}

@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super K> action) {
if (action == null)
throw new NullPointerException();
int i, hi, mc; Object key;
IdentityHashMap<K,V> 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<? super K> 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<K,V>
extends IdentityHashMapSpliterator<K,V>
implements Spliterator<V> {
ValueSpliterator(IdentityHashMap<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) & ~1;
return (lo >= mid) ? null :
new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
expectedModCount);
}

public void forEachRemaining(Consumer<? super V> action) {
if (action == null)
throw new NullPointerException();
int i, hi, mc;
IdentityHashMap<K,V> 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<? super V> 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<K,V>
extends IdentityHashMapSpliterator<K,V>
implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(IdentityHashMap<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) & ~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) {
if (action == null)
throw new NullPointerException();
int i, hi, mc;
IdentityHashMap<K,V> 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>(k, v));

}
}
if (m.modCount == expectedModCount)
return;
}
throw new ConcurrentModificationException();
}

public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> 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>(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;
}
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: