HashMap遍历的方式
Map map = new HashMap<>(); //1、for循环遍历key System.out.println("通过Map.keySet遍历key和value:"); for (String key: map.keySet()){ System.out.println("key:"+key+" value:"+map.get(key)); } //2、for循环遍历value System.out.println("通过Map.values()遍历所有的value,但ey"); for(Object v:map.values()) { System.out.println("value:"+v); } //3、for循环遍历entrySet System.out.println("通过Map.entrySet遍历key和value"); for(Map.Entry entry: map.entrySet()) { System.out.println("Key: "+ entry.getKey()+ " Va"+entry.getValue()); } //4、iterator System.out.println("通过Map.entrySet使用iterator遍历key和va"); Iterator> iterator = map.entrySet().iterator(); while(iterator.hasNext()){ Map.Entry entry = iterator.next(); System.out.println("key:"+entry.getKey()+" value:"+entry.getValue()); }
在遍历HashMap的时候:
Set setStrings = map.keySet() for (String key: setStrings){ System.out.println("key:"+key+" value:"+map.get(key)); }
但是keySet()是如何获取到HashMap的所有的key呢?
public Set keySet() { Set ks = keySet; if (ks == null) { ks = new KeySet(); keySet = ks; } return ks; }
其中keySet、values是AbstractMap中声明的变量:
transient Set keySet; transient Collection values;
调用map.keySet()时,会判断ks是否为空,然后调用new KeySet(),keySet()方法返回一个引用,这个引用指向了HashMap的一个内部类KeySet类:
final class KeySet extends AbstractSet { public final int size() { return size; } public final void clear() { HashMap.this.clear(); } public final Iterator iterator() { return new KeyIterator(); } public final boolean contains(Object o) { return containsKey(o); } public final boolean remove(Object key) { return removeNode(hash(key), key, null, false, true) != null; } public final Spliterator spliterator() { return new KeySpliterator<>(HashMap.this, 0, -1, 0, 0); } public final void forEach(Consumer super K> action) { Node[] 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 e = tab[i]; e != null; e = e.next) action.accept(e.key); } if (modCount != mc) throw new ConcurrentModificationException(); } } }
此内部类继承了AbstractSet,此内部类初始化迭代器产生一个迭代器对象KeyIterator:
final class KeyIterator extends HashIterator implements Iterator { public final K next() { return nextNode().key; } }
在使用增强for循环遍历map.keySet()时,就是调用的KeyIterator.next()方法。KeyIterator类继承了HashIterator迭代器:
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; } }
HashIterator迭代器初始化拿到了next指向map中的第一个元素。当使用keySet集合遍历key时,其实是使用迭代器KeyIterator迭代每个节点的key。
问题:在使用增强for循环遍历map.keySet()时,为什么调用的KeyIterator.next()?对使用增强for循环反编译发现:
Set keys = map.keySet(); Iterator iterator = keys.iterator() while(iterator.hasNext()) { String key = (String)iterator.next(); System.out.println("key:" + key + " value:" (String)map.get(key)); }
增强for循环根本还是iterator()而KeySet定义的iterator()返回值为new KeyIterator(),因此在使用增强for循环遍历map.keySet()时,调用的是KeyIterator.next()。
总结:
- keySet和values和entrySet本质既然一样,就可以通过封装其相同的部分(也就是这里的HashIterator),再各自实现最重要的next方法。
- keySet()方法返回一个内部引用,并指向一个内部类对象,该内部类重写了迭代器方法,当在增强for循环时才调用,并从外部类的table中取值。
![6c75339ae5831d882f67ddfcc8b453b9.png](https://img-blog.csdnimg.cn/img_convert/6c75339ae5831d882f67ddfcc8b453b9.png)