概述
我相信只要写过JAVA的程序要拿99%的都用过HashMap, 其是我们最常用,也是最基础的一个Map.本篇文章将从存储结构、hash规则、扩容策略、迭代器四方面来分析其源代码。
HashMap的迭代起需要记住几个规则:
1:所有迭代器底层共享一份数据,就是那个table表,无论你用何种迭代琦(key的,value的或是entry的)或实例化多少格迭代器,每个迭代器操作的数据都只有一份.
2:无论何种迭代器,底层都是hash迭代器
3:迭代出来的顺序与put进去的顺序是无序的
迭代器的实现
private abstract class HashIterator<E> implements Iterator<E> {
Entry<K,V> next; // next entry to return
int expectedModCount; // For fast-fail
int index; // current slot
Entry<K,V> current; // current entry
HashIterator() {
expectedModCount = modCount;
if (size > 0) { // advance to first entry
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
}
public final boolean hasNext() {
return next != null;
}
final Entry<K,V> nextEntry() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Entry<K,V> e = next;
if (e == null)
throw new NoSuchElementException();
if ((next = e.next) == null) {
Entry[] t = table;
while (index < t.length && (next = t[index++]) == null)
;
}
current = e;
return e;
}
public void remove() {
if (current == null)
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
Object k = current.key;
current = null;
HashMap.this.removeEntryForKey(k);
expectedModCount = modCount;
}
}
由上面的代码可知,hash迭代器保存当前entry和下一个entry,同时记录当前的数组index, expectedModCount表示存储结构更新了多少次,用此来实现快速失败规则。
三种迭代器:
private final class ValueIterator extends HashIterator<V> {
public V next() {
return nextEntry().value;
}
}
private final class KeyIterator extends HashIterator<K> {
public K next() {
return nextEntry().getKey();
}
}
private final class EntryIterator extends HashIterator<Map.Entry<K,V>> {
public Map.Entry<K,V> next() {
return nextEntry();
}
}
快速失败规则
在HashMap中有一个变量
transient int modCount;
记录着这个hashmap结构变化(put,remove)过多少次, 当你新建一个迭代器时,迭代器copy了一份,当你操作迭代器的时候,每次都对比expectedModCount和modConunt是否相等,如果不相等,就失败。
用一句话就是说:在你使用一个迭代器操作map的时候,不要用另外一个迭代器或是其它方式改变map的结构