Map.entrySet() 这个方法返回的是一个Set<Map.Entry<K,V>>,Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value),而Set<Map.Entry<K,V>>表示一个映射项的Set。Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出Key和Value。

下面是遍历Map的四种方法:

 1 public static void main(String[] args) {
2
3
4 Map<String, String> map = new HashMap<String, String>();
5 map.put("1", "value1");
6 map.put("2", "value2");
7 map.put("3", "value3");
8
9 //第一种:普遍使用,二次取值
10 System.out.println("通过Map.keySet遍历key和value:");
11 for (String key : map.keySet()) {
12 System.out.println("key= "+ key + " and value= " + map.get(key));
13 }
14
15 //第二种
16 System.out.println("通过Map.entrySet使用iterator遍历key和value:");
17 Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
18 while (it.hasNext()) {
19 Map.Entry<String, String> entry = it.next();
20 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
21 }
22
23 //第三种:推荐,尤其是容量大时
24 System.out.println("通过Map.entrySet遍历key和value");
25 for (Map.Entry<String, String> entry : map.entrySet()) {
26 System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
27 }
28
29 //第四种
30 System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
31 for (String v : map.values()) {
32 System.out.println("value= " + v);
33 }
34 }

下面是HashMap的源代码:

首先HashMap的底层实现用的时候一个Entry数组

 1 java] view plain copy
2 <pre name="code" class="java"> /**
3 * The table, resized as necessary. Length MUST Always be a power of two.
4 */
5 transient Entry[] table; //声明了一个数组
6 ........
7 public HashMap() {
8 this.loadFactor = DEFAULT_LOAD_FACTOR;
9 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
10 table = new Entry[DEFAULT_INITIAL_CAPACITY];//初始化数组的大小为DEFAULT_INITIAL_CAPACITY(这里是16)
11 init();
12 }</pre><br>

再来看一下Entry是在什么地方定义的,继续上源码,我们在HashMap的源码的674行发现了它的定义,原来他是HashMap的一个内部类,并且实现了Map.Entry接口,

 1 static class Entry<K,V> implements Map.Entry<K,V> {
2 final K key;
3 V value;
4 Entry<K,V> next;
5 final int hash;
6
7 /**
8 * Creates new entry.
9 */
10 Entry(int h, K k, V v, Entry<K,V> n) {
11 value = v;
12 next = n;
13 key = k;
14 hash = h;
15 }
16
17 public final K getKey() {
18 return key;
19 }
20
21 public final V getValue() {
22 return value;
23 }
24
25 public final V setValue(V newValue) {
26 V oldValue = value;
27 value = newValue;
28 return oldValue;
29 }
30
31 public final boolean equals(Object o) {
32 if (!(o instanceof Map.Entry))
33 return false;
34 Map.Entry e = (Map.Entry)o;
35 Object k1 = getKey();
36 Object k2 = e.getKey();
37 if (k1 == k2 || (k1 != null && k1.equals(k2))) {
38 Object v1 = getValue();
39 Object v2 = e.getValue();
40 if (v1 == v2 || (v1 != null && v1.equals(v2)))
41 return true;
42 }
43 return false;
44 }
45
46 public final int hashCode() {
47 return (key==null ? 0 : key.hashCode()) ^
48 (value==null ? 0 : value.hashCode());
49 }
50
51 public final String toString() {
52 return getKey() + "=" + getValue();
53 }
54
55 /**
56 * This method is invoked whenever the value in an entry is
57 * overwritten by an invocation of put(k,v) for a key k that's already
58 * in the HashMap.
59 */
60 void recordAccess(HashMap<K,V> m) {
61 }
62
63 /**
64 * This method is invoked whenever the entry is
65 * removed from the table.
66 */
67 void recordRemoval(HashMap<K,V> m) {
68 }
69 }

  既然这样那我们再看一下Map.Entry这个接口是怎么定义的,原来他是Map的一个内部接口并且定义了一些方法

 1   interface Entry<K,V> {
2 /**
3 * Returns the key corresponding to this entry.
4 *
5 * @return the key corresponding to this entry
6 * @throws IllegalStateException implementations may, but are not
7 * required to, throw this exception if the entry has been
8 * removed from the backing map.
9 */
10 K getKey();
11
12 /**
13 * Returns the value corresponding to this entry. If the mapping
14 * has been removed from the backing map (by the iterator's
15 * <tt>remove</tt> operation), the results of this call are undefined.
16 *
17 * @return the value corresponding to this entry
18 * @throws IllegalStateException implementations may, but are not
19 * required to, throw this exception if the entry has been
20 * removed from the backing map.
21 */
22 V getValue();
23
24 /**
25 * Replaces the value corresponding to this entry with the specified
26 * value (optional operation). (Writes through to the map.) The
27 * behavior of this call is undefined if the mapping has already been
28 * removed from the map (by the iterator's <tt>remove</tt> operation).
29 *
30 * @param value new value to be stored in this entry
31 * @return old value corresponding to the entry
32 * @throws UnsupportedOperationException if the <tt>put</tt> operation
33 * is not supported by the backing map
34 * @throws ClassCastException if the class of the specified value
35 * prevents it from being stored in the backing map
36 * @throws NullPointerException if the backing map does not permit
37 * null values, and the specified value is null
38 * @throws IllegalArgumentException if some property of this value
39 * prevents it from being stored in the backing map
40 * @throws IllegalStateException implementations may, but are not
41 * required to, throw this exception if the entry has been
42 * removed from the backing map.
43 */
44 V setValue(V value);
45
46 /**
47 * Compares the specified object with this entry for equality.
48 * Returns <tt>true</tt> if the given object is also a map entry and
49 * the two entries represent the same mapping. More formally, two
50 * entries <tt>e1</tt> and <tt>e2</tt> represent the same mapping
51 * if<pre>
52 * (e1.getKey()==null ?
53 * e2.getKey()==null : e1.getKey().equals(e2.getKey())) &&
54 * (e1.getValue()==null ?
55 * e2.getValue()==null : e1.getValue().equals(e2.getValue()))
56 * </pre>
57 * This ensures that the <tt>equals</tt> method works properly across
58 * different implementations of the <tt>Map.Entry</tt> interface.
59 *
60 * @param o object to be compared for equality with this map entry
61 * @return <tt>true</tt> if the specified object is equal to this map
62 * entry
63 */
64 boolean equals(Object o);
65
66 /**
67 * Returns the hash code value for this map entry. The hash code
68 * of a map entry <tt>e</tt> is defined to be: <pre>
69 * (e.getKey()==null ? 0 : e.getKey().hashCode()) ^
70 * (e.getValue()==null ? 0 : e.getValue().hashCode())
71 * </pre>
72 * This ensures that <tt>e1.equals(e2)</tt> implies that
73 * <tt>e1.hashCode()==e2.hashCode()</tt> for any two Entries
74 * <tt>e1</tt> and <tt>e2</tt>, as required by the general
75 * contract of <tt>Object.hashCode</tt>.
76 *
77 * @return the hash code value for this map entry
78 * @see Object#hashCode()
79 * @see Object#equals(Object)
80 * @see #equals(Object)
81 */
82 int hashCode();
83 }

  回归前传,为什么HashMap为什么要选择Entry数组来存放key-value?

  因为Entry实现的Map.Entry接口里面定义了getKey(),getValue(),setKey(),setValue()等方法相当于一个javaBean,对键值对进行了一个封装便于后面的操作,从这里我们其实也可以联想到不光是HashMap,譬如LinkedHashMap,TreeMap 等继承自map的容器存储key-value对都应该使用的是Entry只不过组织Entry的形式不一样,HashMap用的是数组加链表的形式,LinkedHashMap用的是链表的形式,TreeMap应该使用的二叉树的形式。

  keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。

  所以,遍历HashMap一共有开头的四种方法,也不难理解为什么有了keySet(),values(),iterator()还要再使用Entry。

Over...

参考:

  1. https://blog.csdn.net/yaomingyang/article/details/78748130
  2. https://blog.csdn.net/kyi_zhu123/article/details/52769469

关于HashMap遍历,为什么要用entry的更多相关文章

  1. Java中HashMap遍历的两种方式

    Java中HashMap遍历的两种方式 转]Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml 第一种: ...

  2. HashMap遍历

    package com.jackey.topic; import java.util.ArrayList;import java.util.HashMap;import java.util.Itera ...

  3. [Java] HashMap遍历的两种方式

    Java中HashMap遍历的两种方式原文地址: http://www.javaweb.cc/language/java/032291.shtml第一种: Map map = new HashMap( ...

  4. HashMap遍历,推荐使用entrySet()

    之前map遍历,偶尔会先去keyset然后再遍历keyset 比如 Map map = new HashMap(); Iterator it = map.keySet().iterator(); wh ...

  5. HashMap 遍历的两种方式及性能比较

    HashMap 是Java开发中经常使用的数据结构.相信HashMap 的基本用法你已经很熟悉了.那么我们该如何遍历HashMap 呢?哪种遍历方式的性能更好呢?本篇文章来为你解决这个疑惑. 一.Ha ...

  6. java 中 HashMap 遍历与删除

    HashMap的遍历 方法一.这是最常见的并且在大多数情况下也是最可取的遍历方式 /** * 在键值都需要时使用 */ Map<Integer, Integer> map = new Ha ...

  7. 史上最全HashMap遍历方式

    java Hashmap Map TreeMap 的几种遍历方式,全网最全,全网最强 package Collec2; import java.util.HashMap; import java.ut ...

  8. HashMap遍历的两种方式

    第一种: Map map = new HashMap(); Iterator iter = map.entrySet().iterator(); while (iter.hasNext()) {    ...

  9. HashMap遍历方式探究

    HashMap的遍历有两种常用的方法,那就是使用keyset及entryset来进行遍历,但两者的遍历速度是有差别的,下面请看实例: package com.HashMap.Test; import ...

随机推荐

  1. Git 沙盒模拟实战(远程篇)

    Git 沙盒模拟实战(远程篇) >---基础篇 远程仓库 远程仓库并不复杂, 在如今的云计算盛行的世界很容易把远程仓库想象成一个富有魔力的东西, 但实际上它们只是你的仓库在另个一台计算机上的拷贝 ...

  2. [Usaco2005 Mar]Out of Hay 干草危机

    题目描述 Bessie 计划调查N (2 <= N <= 2,000)个农场的干草情况,它从1号农场出发.农场之间总共有M (1 <= M <= 10,000)条双向道路,所有 ...

  3. 1V升压5V和1.5V升压5V的集成电路芯片

    1.5V和1V输入,要升压输出5V的集成电路芯片合适? 干电池标准电压是1.5V,放电电压后面在0.9V-1V左右,如果要选用干电池1.5V升压到5V的合适的芯片,需要满足低压1V或者0.9V更好的低 ...

  4. 树莓派安装 Ubuntu 20.04 LTS 碰壁指南

    树莓派安装 Ubuntu 20.04 LTS 碰壁指南 设备 Raspberry 4B 4+32G 系统 Ubuntu 20.04 LTS 1.镜像下载与烧录 镜像下载地址:https://cdima ...

  5. 提供一个HDFS内的文件的路径,对该文件进行创建和删除操作。如果文件所在目录不存在,则自动创建目录。

    1 import java.text.SimpleDateFormat; 2 3 import org.apache.hadoop.fs.FSDataOutputStream; 4 import or ...

  6. 将ffmpeg编译为wasm版本且在浏览器中运行

    2020年大前端技术趋势解读 原创 IMWeb团队 腾讯IMWeb前端团队 5天前

  7. "INVALID" is not a valid start token

    Search · is not a valid start token https://github.com/prometheus/prometheus/search?q=is+not+a+valid ...

  8. Centos GitLab 配置

    如果重启之后,gitlab-ctl restart报"runsv no running"错,先运行下面命令 systemctl start gitlab-runsvdir.serv ...

  9. 页面渲染html的过程

    浏览器渲染页面的一般过程: 1.浏览器解析html源码,然后创建一个 DOM树.并行请求 css/image/js在DOM树中,每一个HTML标签都有一个对应的节点,并且每一个文本也都会有一个对应的文 ...

  10. 【题解】CF952F 2 + 2 != 4

    题目传送门 首先这道题没有翻译,这是很奇怪的,经过了(bai)查(du)字(fan)典(yi)之后,你会发现,什么用都没有-- 楼下的 dalao 们给的解释非常的模糊(果然还是我太弱了),于是我自己 ...