目录
putVal方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i;
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length; //首次添加元素,初始化table,长度为16
if ((p = tab[i = (n - 1) & hash]) == null) //key.hash对应数组的位置还没有值
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k; //对应数组位置有值,可能是链表或红黑树
if (p.hash == hash && //该键值已经存在,头结点p就是要找的值,用e存放找到的对象
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode) //该数组位置存放的是一个红黑树
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else { //该数组位置存放的是链表,但头结点不是该值
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) { //key不存在,放在尾结点
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // 链表长度大于8,转为红黑树
treeifyBin(tab, hash);
break;
}
if (e.hash == hash && //key已存在,退出循环
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e; // e = p.next p = e ;
}
}
if (e != null) { // existing mapping for key 新值替换旧值
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
迭代器的实现方法
迭代器
HashMap内部有三个迭代器:KeyIterator ValueIterator EntryIterator
这三个迭代器都继承一个迭代器 HashIterator,仅实现了next()方法,next()方法均调用nextNode()方法,只是返回值不同
final class KeyIterator extends HashIterator
implements Iterator<K> {
public final K next() { return nextNode().key; }
}
final class ValueIterator extends HashIterator
implements Iterator<V> {
public final V next() { return nextNode().value; }
}
final class EntryIterator extends HashIterator
implements Iterator<Map.Entry<K,V>> {
public final Map.Entry<K,V> next() { return nextNode(); }
}
再看一下HashIterator迭代器中的方法:
abstract class HashIterator {
Node<K,V> next; // next entry to return
Node<K,V> current; // current entry
int expectedModCount; // for fast-fail
int index; // current slot
HashIterator() {
expectedModCount = modCount; //记录hashmap的修改次数,当expect与modCount不同 时,会抛出ConcurrentModificationException异常
Node<K,V>[] t = table;
current = next = null;
index = 0;
if (t != null && size > 0) { // advance to first entry //找到不为空的数组位置头结点
do {} while (index < t.length && (next = t[index++]) == null);
}
}
public final boolean hasNext() {
return next != null;
}
final Node<K,V> nextNode() {
Node<K,V>[] t;
Node<K,V> e = next;
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
if (e == null)
throw new NoSuchElementException();
if ((next = (current = e).next) == null && (t = table) != null) {//next = 链表/树的下一个节点
do {} while (index < t.length && (next = t[index++]) == null); //如果没有下个节点,寻找下一个不为空的数组头结点
}
return e;
}
public final void remove() {
Node<K,V> p = current;
if (p == null) //每次删除需要把current置null,所以不能连续删除两次,必须要先next()移动光标,才能再次删除
throw new IllegalStateException();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
current = null;
K key = p.key;
removeNode(hash(key), key, null, false, false);
expectedModCount = modCount;
}
}
主要是通过移动next光标的位置,指向HashMap中的节点从而获取键值对
迭代器的获取
HashMap本身并没有Iterator()方法,我们遍历HashMap时是通过map.entrySet()获取 Set<Map.Entry<K,V>>然后再调用iterator()方法获取迭代器 : map.entrySet().iterator()
entrySet()方法返回的实际上是一个空的EntrySet
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
EntrySet类的方法:通过EntrySet可以 1. 获取hashmap迭代器 2. 查找hashmap是否包含某个键值 3.删除hashmap某个键值对
但是EntrySet类并没有保存任何关于hashmap中数组的引用,由于它是内部类,通过它的实例可以直接访问hashmap的内部变量及方法,通过直接调用hashmap类的方法,实现查询或删除
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
public final boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Node<K,V> candidate = getNode(hash(key), key);
return candidate != null && candidate.equals(e);
}
public final boolean remove(Object o) {
if (o instanceof Map.Entry) {
Map.Entry<?,?> e = (Map.Entry<?,?>) o;
Object key = e.getKey();
Object value = e.getValue();
return removeNode(hash(key), key, value, true, true) != null;
}
return false;
}
public final Spliterator<Map.Entry<K,V>> spliterator() {
return new EntrySpliterator<>(HashMap.this, 0, -1, 0, 0);
}
public final void forEach(Consumer<? super Map.Entry<K,V>> action) {
Node<K,V>[] tab;
if (action == null)
throw new NullPointerException();
if (size > 0 && (tab = table) != null) {
int mc = modCount;
for (int i = 0; i < tab.length; ++i) {
for (Node<K,V> e = tab[i]; e != null; e = e.next)
action.accept(e);
}
if (modCount != mc)
throw new ConcurrentModificationException();
}
}
}