一 特性
- 键之间的比较不是食用equals 而是使用==也就是比较内存地址
- 可以使用这个存储代理对象
- 支持null值的key和value
- 是非线程安全的,可以借助Collections.synchronizedMap 来获得线程安全的实例
-
二 属性
/**
* 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.
*
* In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
* because it has to have at least one slot with the key == null
* in order to avoid infinite loops in get(), put(), remove()
*/
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;
/**
* Value representing null keys inside tables.
*/
static final Object NULL_KEY = new Object();
三 重要方法
hash
- 计算hash值的方法 ((h << 1) - (h << 8)) & (length - 1)
- nextKeyIndex
- 计算给定位置的hash冲突的解决为止,采用开放寻址方式解决hash冲突
resize
扩容方法 扩容的大小是原来大小的两倍,会创建一个新的数组并将每个元素重进进行hash
四 添加
public V put(K key, V value) {
final Object k = maskNull(key);
retryAfterResize: for (;;) {
final Object[] tab = table;
final int len = tab.length;
int i = hash(k, len);
//这里的循环的为开放寻址法的地址 i = nextKeyIndex(i, len) 来控制的
for (Object item; (item = tab[i]) != null;
i = nextKeyIndex(i, len)) {
if (item == k) {
@SuppressWarnings("unchecked")
V oldValue = (V) tab[i + 1];
tab[i + 1] = value;
return oldValue;
}
}
final int s = size + 1;
// Use optimized form of 3 * s.
// Next capacity is len, 2 * current capacity.
//判断当前已经存在的元素的 2.5倍是否大于数组的长度 扩容后重新retryAfterResize
if (s + (s << 1) > len && resize(len))
continue retryAfterResize;
modCount++;
tab[i] = k;
tab[i + 1] = value;
size = s;
return null;
}
}
五 删除
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];
tab[i + 1] = null;
tab[i] = null;
closeDeletion(i);
return oldValue;
}
if (item == null)
return null;
i = nextKeyIndex(i, len);
}
}
六 获取
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)
return (V) tab[i + 1];
if (item == null)
return null;
//如果都不等于则代表发生了hash冲突,使用开放寻址方式找下一个位置
i = nextKeyIndex(i, len);
}
}
七 resize
private boolean resize(int newCapacity) {
// assert (newCapacity & -newCapacity) == newCapacity; // power of 2 新大小是原来的两倍
int newLength = newCapacity * 2;
Object[] oldTable = table;
int oldLength = oldTable.length;
if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
if (size == MAXIMUM_CAPACITY - 1)
throw new IllegalStateException("Capacity exhausted.");
return false;
}
if (oldLength >= newLength)
return false;
Object[] newTable = new Object[newLength];
//重新进行更新hash槽位的过程
for (int j = 0; j < oldLength; j += 2) {
Object key = oldTable[j];
if (key != null) {
Object value = oldTable[j+1];
oldTable[j] = null;
oldTable[j+1] = null;
int i = hash(key, newLength);
while (newTable[i] != null)
i = nextKeyIndex(i, newLength);
newTable[i] = key;
newTable[i + 1] = value;
}
}
table = newTable;
return true;
}