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. SpringBoot 好“吃”的启动原理

    原创:西狩 编写日期 / 修订日期:2020-12-30 / 2020-12-30 版权声明:本文为博主原创文章,遵循 CC BY-SA-4.0 版权协议,转载请附上原文出处链接和本声明. 不正经的前 ...

  2. 卷积神经网络学习笔记——SENet

    完整代码及其数据,请移步小编的GitHub地址 传送门:请点击我 如果点击有误:https://github.com/LeBron-Jian/DeepLearningNote 这里结合网络的资料和SE ...

  3. 1V升压到3V的芯片,1V升压3.3V电路图

    1V升压到3V和1V升压3.3V的升压芯片? PW5100 是一款效率很大.低功耗.低纹波.高工作频率的 PFM 同步升压 DC/DC 变换器.输出电压可选固定输出值,从 3.0V,3.3V, 5.0 ...

  4. Development desciptor

    概述与作用: 部署描述符是用于描述Web应用程序的元数据,并为Java EE Web应用程序服务器部署和运行Web应用程序提供指令.从传统上来说,所有元数据都来自于部署描述符文件/WEB-INF/we ...

  5. day131:2RenMJ:2RenMJ游戏简介&部署MJ项目到本地

    目录 1.游戏简介 1.如何做出一款麻将游戏? 2.麻将运行界面 3.麻将项目所用技术快速概览 4.web开发 / 游戏开发 / APP开发 比较 5.firefly游戏框架介绍 2.部署麻将项目到本 ...

  6. 浅谈linux IO csy 360技术 2021-01-18

    浅谈linux IO csy 360技术 2021-01-18

  7. Spring 动态代理时是如何解决循环依赖的?为什么要使用三级缓存?

    前言 在研究 『 Spring 是如何解决循环依赖的 』 的时候,了解到 Spring 是借助三级缓存来解决循环依赖的. 同样在上一节留下了疑问: 循环依赖为什么要使用三级缓存?而不是使用二级缓存? ...

  8. 使用 Tye 辅助开发 k8s 应用竟如此简单(一)

    最近正巧在进行 Newbe.Claptrap 新版本的开发,其中使用到了 Tye 来辅助 k8s 应用的开发.该系列我们就来简单了解一下其用法. Newbe.Claptrap 是一个用于轻松应对并发问 ...

  9. Java面试,面试题

    Java面试,面试题 HashMap,HashTable,ConcurrentHash的共同点和区别 HashMap HashTable ConcurrentHashMap ArrayList和Lin ...

  10. (七)整合 Redis集群 ,实现消息队列场景

    整合 Redis集群 ,实现消息队列场景 1.Redis集群简介 1.1 RedisCluster概念 2.SpringBoot整合Redis集群 2.1 核心依赖 2.2 核心配置 2.3 参数渲染 ...