循环遍历一个 HashMap 可以通过下面的方式
for (Map.Entry entry : hashMap.entrySet()) { Object key = entry.getKey(); Object value = entry.getValue(); ....}
或者用迭代器
Iterator iterator = hashMap.entrySet().iterator();while (iterator.hasNext()) { Object object = iterator.next(); ....}
其实是一样的 foreach 底层就是调用了 iterator.next() 方法。
下面通过源码分析一下究竟如何遍历一个map和遍历一个map具体发生了哪些事情。
进入到这个 entrySet() 方法里面
public Set> entrySet() { Set > es; return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}final class EntrySet extends AbstractSet > { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator > iterator() { return new EntryIterator(); } ...}
如果是空的就new一个EntrtSet(),如果不是空的就直接返回,在看下EntrySet这个类,里面有一个 iterator() 方法,new一个EntryIterator()
final class EntryIterator extends HashIterator implements Iterator> { public final Map.Entry next() { return nextNode(); }}abstract class HashIterator { Node next; // next entry to return Node current; // current entry int expectedModCount; // for fast-fail int index; // current slot HashIterator() { expectedModCount = modCount; Node [] 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 nextNode() { Node [] t; Node e = next; if (modCount != expectedModCount) throw new ConcurrentModificationException(); if (e == null) throw new NoSuchElementException(); if ((next = (current = e).next) == null && (t = table) != null) { do {} while (index < t.length && (next = t[index++]) == null); } return e; } public final void remove() { Node p = current; if (p == null) throw new IllegalStateException(); if (modCount != expectedModCount) throw new ConcurrentModificationException(); current = null; K key = p.key; removeNode(hash(key), key, null, false, false); expectedModCount = modCount; }}
这个 EntryIterator 继承自 HashIterator 实现了 Iterator 接口,这里的 next() 方法直接调用的是HashIterator类的 nextNode() 方法,从这可以看出来这个next方法其实返回的就是 Node 节点的 next 字段。Node节点是这样的
static class Nodeimplements Map.Entry { final int hash; final K key; V value; Node next; 。。。}
综上所述,用entrySet这种方式遍历一个map,其实就是获取到hashmap最底层的数组,从数组的第0个位置一直开始遍历,如果数组的位置是个链表,那么把链表也遍历一遍。回过头来看这个方法的名字 entrySet,hashmap的数组里面放的是Node,这个Node就是Map.Entry的实现类,entrySet 顾名思义就是所有 entry 的一个set集合。