上篇文章(http://www.jianshu.com/p/a122c79ee60c)
我们分析了HashMap的构造和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[] 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[] newTable = makeTable(newCapacity);
if (size != 0) {
int newMask = newCapacity - 1;
for (int i = 0; i < oldCapacity; i++) {
for (HashMapEntry e = oldTable[i]; e != null;) {
HashMapEntry oldNext = e.next;
int newIndex = e.hash & newMask;
HashMapEntry newNext = newTable[newIndex];
newTable[newIndex] = e;
e.next = newNext;
e = oldNext;
}
}
}
}
首先得到一个新的容量newCapacity,如果等于旧容量的2倍就调用doubleCapacity()方法,这个方法在上一篇已经解析过了,这边就不再说了,makeTable方法创建一个新的数组,上篇文章也解析过了,下面着重看看这个循环
if (size != 0) {
int newMask = newCapacity - 1;
for (int i = 0; i < oldCapacity; i++) {
for (HashMapEntry e = oldTable[i]; e != null;) {
HashMapEntry oldNext = e.next;
int newIndex = e.hash & newMask;
HashMapEntry newNext = newTable[newIndex];
newTable[newIndex] = e;
e.next = newNext;
e = oldNext;
}
}
}
首先计算出数据在新的数组当中的index下标,如果next有数据又改变了链表的顺利,总之就是把旧数组当中的数据添加到了新的数组当中,然后调用父类的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对象参数,然后调用HashMap的put方法添加数据。
get方法
public V get(Object key) {
if (key == null) {
HashMapEntry e = entryForNullKey;
return e == null ? null : e.value;
}
int hash = Collections.secondaryHash(key);
HashMapEntry[] tab = table;
for (HashMapEntry 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[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry 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,调用removeNullKey方法
private V removeNullKey() {
HashMapEntry e = entryForNullKey;
if (e == null) {
return null;
}
entryForNullKey = null;
modCount++;
size--;
postRemove(e);
return e.value;
}
设置entryForNullKey对象为null。
key不为空
int hash = Collections.secondaryHash(key);
HashMapEntry[] tab = table;
int index = hash & (tab.length - 1);
for (HashMapEntry 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,然后循环
如果删除的数据在index位置,就把index位置的对象的下一个对象赋值给数组的index位置。
如果删除的数据在index位置的链表中间就把链表中间的这个数据删除掉,然后把中间数据的头和尾连接在一起。
结束语
到此HashMap的常用方法都分析完了,通过看源码对HashMap有了更深的理解。