上篇文章(http://www.reibang.com/p/a122c79ee60c)
我們分析了HashMap的構(gòu)造和put方法羡铲,這篇文章來看看它的其他方法
putAll
@Override
public void putAll(Map<? extends K, ? extends V> map) {
ensureCapacity(map.size());
super.putAll(map);
}
我們來看看 ensureCapacity(map.size());方法
private void ensureCapacity(int numMappings) {
int newCapacity = Collections.roundUpToPowerOfTwo(capacityForInitSize(numMappings));
HashMapEntry<K, V>[] oldTable = table;
int oldCapacity = oldTable.length;
if (newCapacity <= oldCapacity) {
return;
}
if (newCapacity == oldCapacity * 2) {
doubleCapacity();
return;
}
// We're growing by at least 4x, rehash in the obvious way
HashMapEntry<K, V>[] newTable = makeTable(newCapacity);
if (size != 0) {
int newMask = newCapacity - 1;
for (int i = 0; i < oldCapacity; i++) {
for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
HashMapEntry<K, V> oldNext = e.next;
int newIndex = e.hash & newMask;
HashMapEntry<K, V> newNext = newTable[newIndex];
newTable[newIndex] = e;
e.next = newNext;
e = oldNext;
}
}
}
}
首先得到一個新的容量newCapacity忿族,如果等于舊容量的2倍就調(diào)用doubleCapacity()方法陶冷,這個方法在上一篇已經(jīng)解析過了,這邊就不再說了沮脖,makeTable方法創(chuàng)建一個新的數(shù)組,上篇文章也解析過了,下面著重看看這個循環(huán)
if (size != 0) {
int newMask = newCapacity - 1;
for (int i = 0; i < oldCapacity; i++) {
for (HashMapEntry<K, V> e = oldTable[i]; e != null;) {
HashMapEntry<K, V> oldNext = e.next;
int newIndex = e.hash & newMask;
HashMapEntry<K, V> newNext = newTable[newIndex];
newTable[newIndex] = e;
e.next = newNext;
e = oldNext;
}
}
}
首先計算出數(shù)據(jù)在新的數(shù)組當中的index下標饲鄙,如果next有數(shù)據(jù)又改變了鏈表的順利凄诞,總之就是把舊數(shù)組當中的數(shù)據(jù)添加到了新的數(shù)組當中,然后調(diào)用父類的putAll方法
public void putAll(Map<? extends K, ? extends V> map) {
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
首先遍歷map對象參數(shù)忍级,然后調(diào)用HashMap的put方法添加數(shù)據(jù)帆谍。
get方法
public V get(Object key) {
if (key == null) {
HashMapEntry<K, V> e = entryForNullKey;
return e == null ? null : e.value;
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)];
e != null; e = e.next) {
K eKey = e.key;
if (eKey == key || (e.hash == hash && key.equals(eKey))) {
return e.value;
}
}
return null;
}
如果key==null,就返回entryForNullKey對象轴咱,不為null汛蝙,首先計算hash值,然后計算index下標朴肺,得到對象
如果eKey == key || (e.hash == hash && key.equals(eKey)) 條件成立窖剑,就返回value。
remove方法
@Override
public V remove(Object key) {
if (key == null) {
return removeNullKey();
}
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry<K, V> e = tab[index], prev = null;
e != null; prev = e, e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
if (prev == null) {
tab[index] = e.next;
} else {
prev.next = e.next;
}
modCount++;
size--;
postRemove(e);
return e.value;
}
}
return null;
}
如果key為null戈稿,調(diào)用removeNullKey方法
private V removeNullKey() {
HashMapEntry<K, V> e = entryForNullKey;
if (e == null) {
return null;
}
entryForNullKey = null;
modCount++;
size--;
postRemove(e);
return e.value;
}
設(shè)置entryForNullKey對象為null西土。
key不為空
int hash = Collections.secondaryHash(key);
HashMapEntry<K, V>[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry<K, V> e = tab[index], prev = null;
e != null; prev = e, e = e.next) {
if (e.hash == hash && key.equals(e.key)) {
if (prev == null) {
tab[index] = e.next;
} else {
prev.next = e.next;
}
modCount++;
size--;
postRemove(e);
return e.value;
}
}
首先得到index,然后循環(huán)
如果刪除的數(shù)據(jù)在index位置器瘪,就把index位置的對象的下一個對象賦值給數(shù)組的index位置翠储。
如果刪除的數(shù)據(jù)在index位置的鏈表中間就把鏈表中間的這個數(shù)據(jù)刪除掉,然后把中間數(shù)據(jù)的頭和尾連接在一起橡疼。
結(jié)束語
到此HashMap的常用方法都分析完了援所,通過看源碼對HashMap有了更深的理解。