1. IdentityHashMap概述
IdentityHashMap是一致性哈希表,使用引用相等,而不是equals方法来比较两个对象的相等性。因此,IdentityHashMap中,如果存在两个键key1和key2,当且仅当key1==key2时,两个键相等,而其他大部分的哈希表,当且仅当k1 == null ? k2 == null : k1.equals(k2)时,两个键才认为是相等的。
IdentityHashMap使用System.identityHashCode来确定对象的哈希码,该方法返回对象的地址。
看下IdentityHashMap的存储原理图,和HashMap不同,HashMap是通过数组+拉链法存储元素并解决哈希冲突的。IdentityHashMap将所有的key和value都存储到Object[]数组table中,并且key和value相邻存储,当出现哈希冲突时,会往下遍历数组,直到找到一个空闲的位置。注意,数组第一个位置存储的是key,第二个位置存储的是value。因此奇数位置处存储的是key,偶数位置处存储的是value。
2. 私有变量
//哈希表的默认容量
private static final int DEFAULT_CAPACITY = 32;
//哈希表的最小容量
private static final int MINIMUM_CAPACITY = 4;
//哈希表的最大容量,其中包括了一个键为null的键值对
private static final int MAXIMUM_CAPACITY = 1 << 29;
//哈希表内部存储的数组
transient Object[] table;
//哈希表存储的键值对数量
int size;
//哈希表的修改次数
transient int modCount;
//存储键为null的key,如果键为null,实际用NULL_KEY存储
static final Object NULL_KEY = new Object();
注意,IdentityHashMap的加载因子为2/3。
3. 构造函数
//默认构造函数,容量为32,加载因子为2/3,最多可存储32*2/3=21个键值对
public IdentityHashMap() {
init(DEFAULT_CAPACITY);
}
//根据指定容量构造
public IdentityHashMap(int expectedMaxSize) {
if (expectedMaxSize < 0)
throw new IllegalArgumentException("expectedMaxSize is negative: "
+ expectedMaxSize);
init(capacity(expectedMaxSize));
}
//返回一个介于MINIMUM_CAPACITY和MAXIMUM_CAPACITY,且大于3*expectedMaxSize/2的值
//如果该值不存在,返回MAXIMUM_CAPACITY
private static int capacity(int expectedMaxSize) {
// assert expectedMaxSize >= 0;
return
(expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
(expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
}
//初始化内部存储数组table,table数组大小为参数initCapacity的两倍