学习笔记-Map集合的遍历
Map集合的兩種遍歷方式
通過查看Map集合的API發現沒有iterator方法,那么雙列集合如何迭代呢?一、Map集合的遍歷之鍵找值
基本思路: * 先獲取所有鍵的集合 * 遍歷鍵的集合,獲取到每一個鍵 * 根據鍵找值 注意--這里我們查看API可以發現Map接口中有一個方法為: Set<K> keySet():獲取集合中所有鍵的集合 可以看到keySet方法返回了一個Set集合,而Set集合中有迭代器iterator,這樣就可以運用Set集合的特性來達到對Map集合的遍歷示例
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set;public class Map_Iterator {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("張三", 23);map.put("李四", 24);map.put("王五", 25);map.put("趙六", 26);Set<String> keySet = map.keySet(); // 獲取所有鍵的集合Iterator<String> it = keySet.iterator(); // 獲取迭代器while (it.hasNext()) { // 判斷集合中是否有元素String key = it.next(); // 獲取每一個鍵Integer value = map.get(key); // 根據鍵獲取值System.out.println(key + "=" + value);}}}上面也可以使用增強for循環遍歷
import java.util.HashMap; import java.util.Map;public class Map_Iterator {public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("張三", 23);map.put("李四", 24);map.put("王五", 25);map.put("趙六", 26);for(String key : map.keySet()) { //map.keySet()是所有鍵的集合System.out.println(key + "=" + map.get(key));//這里的map.get方法是HashMap中的get}}}二、Map集合的遍歷之鍵值對對象找鍵和值
鍵值對對象找鍵和值的思路: * 獲取所有鍵值對對象的集合 * 遍歷鍵值對對象的集合,獲取到每一個鍵值對對象 * 根據鍵值對對象找鍵和值 注意--這里我們查看API可以發現Map接口中有一個方法為: Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射關系的Set視圖 Map.Entry(注意這個.)說明Entry是Map的內部接口,將鍵和值封裝成了Entry對象,并存儲在Set集合中示例
import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set;public class Map_Iterator2{public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("張三", 23);map.put("李四", 24);map.put("王五", 25);map.put("趙六", 26);//Map.Entry說明Entry是Map的內部接口,將鍵和值封裝成了Entry對象,并存儲在Set集合中Set<Map.Entry<String, Integer>> entrySet = map.entrySet();//獲取每一個對象Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();while(it.hasNext()) {//獲取每一個Entry對象Map.Entry<String, Integer> en = it.next(); //父類引用指向子類對象 //Entry<String, Integer> en = it.next(); //這樣寫等同于上面,這里的Entry也是Map中的Entry接口String key = en.getKey(); //根據鍵值對對象獲取鍵Integer value = en.getValue(); //根據鍵值對對象獲取值System.out.println(key + "=" + value);}}}產生的疑問:?
上面代碼中Map.Entry<String, Integer> en = it.next(); 是說父類引用指向子類對象,為什么?接下來我們來分析一下上述程序的具體實現過程:
先看一下HashMap的底層的一些變量:
第一步Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
上面這一步map調用的entrySet() 方法其實是HashMap中重寫了Map接口的 entrySet() 方法的entrySet().源碼如下:
從源碼可以看出這個臨時變量entrySet是等于null的,也就是說每次都是new EntrySet();接下來看下面的EntrySet類:
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();}} }程序走到了:Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
而我們可以從源碼看到,EntrySet類中重寫了iterator方法。返回的是一個new EntryIterator(),接下來看EntryIterator類
可以看到EntryIterator類繼承了HashIterator,而且EntryIterator中有一個next()方法,返回一個nextNode(); 這個返回值其實是在HashIterator中;再看它的源碼:
transient Node<K,V>[] table;transient int modCount;abstract class HashIterator {Node<K,V> next; // next entry to returnNode<K,V> current; // current entryint expectedModCount; // for fast-failint index; // current slotHashIterator() {expectedModCount = modCount;Node<K,V>[] t = table;current = next = null;index = 0;if (t != null && size > 0) { // advance to first entrydo {} 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) {do {} while (index < t.length && (next = t[index++]) == null);}return e;}public final void remove() {Node<K,V> 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的變量,這個變量是在table數組中取得,索引是從0遞增的,即先入先出原則。構造初期會從0開始找有值的索引位置,找到后將這個Node賦值給next;然后要遍歷的時候是調用nextNode()方法,這個方法是先判斷next.next是否為空,如果為空繼續往上找有值的索引位置,如果不為空就找next.next。這樣就能都遍歷出來了,是從索引0到table.length去一個個尋找遍歷的。
此時程序經歷了while(it.hasNext()) { Map.Entry<String, Integer> en = it.next();已經遍歷完了HashMap集合;這里的 it.next() 返回了 nextNode(); 方法,而nextNode()返回了一個e;Node<K,V> e = next;Node為HashMap集合的一個靜態內部類,它實現了Map.Entry接口;
源碼如下:
所以程序中String key = en.getKey(); Integer value = en.getValue();調用的就是Node類中的方法;所以就可以說Map.Entry<String, Integer> en = it.next(); 是父類引用指向子類對象.
上述遍歷代碼也可以用增強for循環實現
代碼如下:
import java.util.HashMap; import java.util.Map; import java.util.Map.Entry;public class Map_Iterator2{public static void main(String[] args) {Map<String, Integer> map = new HashMap<>();map.put("張三", 23);map.put("李四", 24);map.put("王五", 25);map.put("趙六", 26);for (Map.Entry<String, Integer> en : map.entrySet()) {System.out.println(en.getKey() + "=" + en.getValue());}}}總結
以上是生活随笔為你收集整理的学习笔记-Map集合的遍历的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux svn log 乱码,解决p
- 下一篇: Linux 用户名、主机添加背景色