IdentityHashMap
IdentityHashMap和HashMap長的挺類似
public class IdentityHashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, java.io.Serializable, Cloneable
和HashMap一樣繼承和實現了同樣的抽象類和介面,是一種特殊的HashMap,他的巧妙之處在於HashMap是用傳入的key值物件判斷是否相等,相等就覆蓋上一個value,即“equals”,而IdentityHashMap是通過key的引用來判斷的,即使值相等,但引用地址不同的話也不會覆蓋。
示例程式碼:
Map<Integer,String> map1 = new HashMap<Integer,String>();
Map<Integer,String> map2 = new IdentityHashMap<Integer, String>();
Integer a = new Integer(123);
Integer b = new Integer(123);
map1.put(a,"1");
map1.put(b,"1");
map2.put(a,"1");
map2.put(b,"1");
System.out.println("hashmap: "+map1);
System.out.println("IdentityHashMap: "+map2);
}
//輸出結果
hashmap: {123=1}
IdentityHashMap: {123=1, 123=1}
我們來看看他的實現
//使用的是"=="
private static Object maskNull(Object key) {
return (key == null ? NULL_KEY : key);
}
可以看到,IdentityHashMap底層是一個object[ ]
private void init(int initCapacity) {
table = new Object[2 * initCapacity];
}
那既然沒有像hashmap使用連結串列,那他遇到了hash衝突後,且key不一樣該如何解決了
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);
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.
if (s + (s << 1) > len && resize(len))
continue retryAfterResize;
modCount++;
tab[i] = k;
tab[i + 1] = value;
size = s;
return null;
}
}
put方法裡,可以看到,他會在Object[ ]
+1+1的去尋找下一個有效的索引位置,並插入,但是長度是有限的,這個我們可以在上面的init方法中看到,這就要涉及到他的擴容策略了
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];
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;
}
可以看到,他的新表長度為之前長度的2倍,然後會把舊錶的值全部重新複製到新的表裡