日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习笔记-Map集合的遍历

發(fā)布時間:2023/12/9 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习笔记-Map集合的遍历 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Map集合的兩種遍歷方式

通過查看Map集合的API發(fā)現(xiàn)沒有iterator方法,那么雙列集合如何迭代呢?
一、Map集合的遍歷之鍵找值
基本思路: * 先獲取所有鍵的集合 * 遍歷鍵的集合,獲取到每一個鍵 * 根據(jù)鍵找值 注意--這里我們查看API可以發(fā)現(xiàn)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); // 根據(jù)鍵獲取值System.out.println(key + "=" + value);}}}
上面也可以使用增強for循環(huán)遍歷
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集合的遍歷之鍵值對對象找鍵和值
鍵值對對象找鍵和值的思路: * 獲取所有鍵值對對象的集合 * 遍歷鍵值對對象的集合,獲取到每一個鍵值對對象 * 根據(jù)鍵值對對象找鍵和值 注意--這里我們查看API可以發(fā)現(xiàn)Map接口中有一個方法為: Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射關系的Set視圖 Map.Entry(注意這個.)說明Entry是Map的內(nèi)部接口,將鍵和值封裝成了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的內(nèi)部接口,將鍵和值封裝成了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(); //根據(jù)鍵值對對象獲取鍵Integer value = en.getValue(); //根據(jù)鍵值對對象獲取值System.out.println(key + "=" + value);}}}
產(chǎn)生的疑問:?
上面代碼中Map.Entry<String, Integer> en = it.next(); 是說父類引用指向子類對象,為什么?

接下來我們來分析一下上述程序的具體實現(xiàn)過程:
先看一下HashMap的底層的一些變量:

transient Node<K,V>[] table; //存儲數(shù)據(jù)的Node數(shù)組transient Set<java.util.Map.Entry<K,V>> entrySet;transient int size; //map中存放數(shù)據(jù)的個數(shù),不等于table.lengthtransient int modCount; //修改的次數(shù),防止int threshold; //臨界值final float loadFactor; //擴展因子,一般情況下threshold=table.length*loadFactor;//構造一個空的HashMap時,只有l(wèi)oadFactor被賦值為默認的0.75。代碼如下:public HashMapMmc(){this.loadFactor=DEFAULT_LOAD_FACTOR;}

第一步Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
上面這一步map調(diào)用的entrySet() 方法其實是HashMap中重寫了Map接口entrySet() 方法的entrySet().源碼如下:

transient Set<Map.Entry<K,V>> entrySet;public Set<Map.Entry<K,V>> entrySet() {Set<Map.Entry<K,V>> es;return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;}final class EntrySet extends AbstractSet<Map.Entry<K,V>> {...

從源碼可以看出這個臨時變量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

final class EntryIterator extends HashIterator implements Iterator<Map.Entry<K,V>> {public final Map.Entry<K,V> next() { return nextNode(); }}

可以看到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數(shù)組中取得,索引是從0遞增的,即先入先出原則。構造初期會從0開始找有值的索引位置,找到后將這個Node賦值給next;然后要遍歷的時候是調(diào)用nextNode()方法,這個方法是先判斷next.next是否為空,如果為空繼續(xù)往上找有值的索引位置,如果不為空就找next.next。這樣就能都遍歷出來了,是從索引0table.length去一個個尋找遍歷的。

此時程序經(jīng)歷了while(it.hasNext()) { Map.Entry<String, Integer> en = it.next();已經(jīng)遍歷完了HashMap集合;這里的 it.next() 返回了 nextNode(); 方法,而nextNode()返回了一個e;Node<K,V> e = next;NodeHashMap集合的一個靜態(tài)內(nèi)部類,它實現(xiàn)了Map.Entry接口;
源碼如下:

static class Node<K,V> implements Map.Entry<K,V> {final int hash;final K key;V value;Node<K,V> next;Node(int hash, K key, V value, Node<K,V> next) {this.hash = hash;this.key = key;this.value = value;this.next = next;}public final K getKey() { return key; }public final V getValue() { return value; }public final String toString() { return key + "=" + value; }public final int hashCode() {return Objects.hashCode(key) ^ Objects.hashCode(value);}public final V setValue(V newValue) {V oldValue = value;value = newValue;return oldValue;}public final boolean equals(Object o) {if (o == this)return true;if (o instanceof Map.Entry) {Map.Entry<?,?> e = (Map.Entry<?,?>)o;if (Objects.equals(key, e.getKey()) &&Objects.equals(value, e.getValue()))return true;}return false;}}

所以程序中String key = en.getKey(); Integer value = en.getValue();調(diào)用的就是Node類中的方法;所以就可以說Map.Entry<String, Integer> en = it.next(); 是父類引用指向子類對象.

上述遍歷代碼也可以用增強for循環(huán)實現(xiàn)

代碼如下:

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集合的遍历的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。