Java学习之HashMap: 如何正确实现Map的entrySet()方法

不推荐使用 keySet() 遍历HashMap,建议使用entrySet() 在Java编程中,HashMap是一种非常常见的数据结构。我们经常需要对其中的键值对进行遍历。通常有多种方法可以遍历HashMap,其中一种方法是使用keySet()方法。然而,很多Java大佬并不推荐这种方法。为什么呢?keySet() 阅读详情

转载链接:http://410063005.iteye.com/blog/1676845

通过继承AbstractMap我们可以很容易实现自己的Map,我们只需要实现唯一的抽象的entrySet()方法。 以下是来自《Jav编程思想》(第四版第17章的例子),继承AbstractMap实现了自己的SlowMap。 另外还应该注意, 如果要创建自己的Map,还必须同时定义Map.Entry的实现。

 

总结起来实现自定义Map需要以下两个步骤:

  1. 继承AbstractMap需要实现entrySet()方法
  2. 实现自己的Map.Entry

Java代码   收藏代码
  1. //: containers/MapEntry.java  
  2. // A simple Map.Entry for sample Map implementations.  
  3. import java.util.*;  
  4.   
  5. public class MapEntry<K,V> implements Map.Entry<K,V> {  
  6.   private K key;  
  7.   private V value;  
  8.   public MapEntry(K key, V value) {  
  9.     this.key = key;  
  10.     this.value = value;  
  11.   }  
  12.   public K getKey() { return key; }  
  13.   public V getValue() { return value; }  
  14.   public V setValue(V v) {  
  15.     V result = value;  
  16.     value = v;  
  17.     return result;  
  18.   }  
  19.   public int hashCode() {  
  20.     return (key==null ? 0 : key.hashCode()) ^  
  21.       (value==null ? 0 : value.hashCode());  
  22.   }  
  23.   public boolean equals(Object o) {  
  24.     if(!(o instanceof MapEntry)) return false;  
  25.     MapEntry me = (MapEntry)o;  
  26.     return  
  27.       (key == null ?  
  28.        me.getKey() == null : key.equals(me.getKey())) &&  
  29.       (value == null ?  
  30.        me.getValue()== null : value.equals(me.getValue()));  
  31.   }  
  32.   public String toString() { return key + "=" + value; }  
  33. } ///:~  
  34.   
  35.   
  36.   
  37. //: containers/SlowMap.java  
  38. // A Map implemented with ArrayLists.  
  39. import java.util.*;  
  40. import net.mindview.util.*;  
  41.   
  42. public class SlowMap<K,V> extends AbstractMap<K,V> {  
  43.   private List<K> keys = new ArrayList<K>();  
  44.   private List<V> values = new ArrayList<V>();  
  45.   public V put(K key, V value) {  
  46.     V oldValue = get(key); // The old value or null  
  47.     if(!keys.contains(key)) {  
  48.       keys.add(key);  
  49.       values.add(value);  
  50.     } else  
  51.       values.set(keys.indexOf(key), value);  
  52.     return oldValue;  
  53.   }  
  54.   public V get(Object key) { // key is type Object, not K  
  55.     if(!keys.contains(key))  
  56.       return null;  
  57.     return values.get(keys.indexOf(key));  
  58.   }  
  59.   public Set<Map.Entry<K,V>> entrySet() {  
  60.     Set<Map.Entry<K,V>> set= new HashSet<Map.Entry<K,V>>();  
  61.     Iterator<K> ki = keys.iterator();  
  62.     Iterator<V> vi = values.iterator();  
  63.     while(ki.hasNext())  
  64.       set.add(new MapEntry<K,V>(ki.next(), vi.next()));  
  65.     return set;  
  66.   }  
  67.   public static void main(String[] args) {  
  68.     SlowMap<String,String> m= new SlowMap<String,String>();  
  69.     m.putAll(Countries.capitals(15));  
  70.     System.out.println(m);  
  71.     System.out.println(m.get("BULGARIA"));  
  72.     System.out.println(m.entrySet());  
  73.   }  
  74. } /* Output: 
  75. {CAMEROON=Yaounde, CHAD=N'djamena, CONGO=Brazzaville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, CENTRAL AFRICAN REPUBLIC=Bangui, BOTSWANA=Gaberone, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, DJIBOUTI=Dijibouti} 
  76. Sofia 
  77. [CAMEROON=Yaounde, CHAD=N'djamena, CONGO=Brazzaville, CAPE VERDE=Praia, ALGERIA=Algiers, COMOROS=Moroni, CENTRAL AFRICAN REPUBLIC=Bangui, BOTSWANA=Gaberone, BURUNDI=Bujumbura, BENIN=Porto-Novo, BULGARIA=Sofia, EGYPT=Cairo, ANGOLA=Luanda, BURKINA FASO=Ouagadougou, DJIBOUTI=Dijibouti] 
  78. *///:~  

 以上是一个参考实现。这个解决方案看起来很简单并且没什么问题,但这并不是一个恰当的实现。主要问题是它创建了键和值的副本。entrySet()的恰当实现 应该在Map中提供视图,而不是副本,并且这个视图允许对原始的映射表进行修改,而副本则不行。

 

可以参考源码来学习正确的entrySet()应该如何实现。首先先看Map中entrySet()的声明

Java代码   收藏代码
  1. public interface Map<K,V> {  
  2.     /** 
  3.      * Returns a {@link Set} view of the mappings contained in this map. 
  4.      * The set is backed by the map, so changes to the map are 
  5.      * reflected in the set, and vice-versa.  If the map is modified 
  6.      * while an iteration over the set is in progress (except through 
  7.      * the iterator's own <tt>remove</tt> operation, or through the 
  8.      * <tt>setValue</tt> operation on a map entry returned by the 
  9.      * iterator) the results of the iteration are undefined.  The set 
  10.      * supports element removal, which removes the corresponding 
  11.      * mapping from the map, via the <tt>Iterator.remove</tt>, 
  12.      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt> and 
  13.      * <tt>clear</tt> operations.  It does not support the 
  14.      * <tt>add</tt> or <tt>addAll</tt> operations. 
  15.      * 
  16.      * @return a set view of the mappings contained in this map 
  17.      */  
  18.     Set<Map.Entry<K, V>> entrySet();  
  19. }  
注释文档明确指出,entrySet()返回的Set应该是Map所代表的映射表的一个View。 对Map的修改应该会反映到这个Set,反过来对这个Set的修改也会反映到Map 。特别地,当在这个Set上进行迭代的过程中,如果修改了Map(除非是通过这个Set的迭代器进行remov()e或setValue()操作),那么迭代过程产生的结果是不确定的。 

 

再看HashMap中entrySet()方法的实现

Java代码   收藏代码
  1. public Set<Map.Entry<K,V>> entrySet() {  
  2. urn entrySet0();  
  3. }  
  4.   
  5. private Set<Map.Entry<K,V>> entrySet0() {  
  6.     Set<Map.Entry<K,V>> es = entrySet;  
  7.     return es != null ? es : (entrySet = new EntrySet());  
  8. }  
  9.   
  10. private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {  
  11.     public Iterator<Map.Entry<K,V>> iterator() {  
  12.         return newEntryIterator();  
  13.     }  
  14.     public boolean contains(Object o) {  
  15.         if (!(o instanceof Map.Entry))  
  16.             return false;  
  17.         Map.Entry<K,V> e = (Map.Entry<K,V>) o;  
  18.         Entry<K,V> candidate = getEntry(e.getKey());  
  19.         return candidate != null && candidate.equals(e);  
  20.     }  
  21.     public boolean remove(Object o) {  
  22.         return removeMapping(o) != null;  
  23.     }  
  24.     public int size() {  
  25.         return size;  
  26.     }  
  27.     public void clear() {  
  28.         HashMap.this.clear();  
  29.     }  
  30. }  

 EntrySet是HashMap的一个内部类,它继承自AbstractSet,必须需要实现iterator()和size()两个抽象方法。而HashMap的entrySet()不过是返回了EntrySet的一个实例。

注意,与我们之前定义的SlowMap的entrySet()相比,这里的entrySet()实现中没有进行任何创建副本的操作。不难发现,remove()和clear()等方法,最终会调用到EntrySet所在的外部对象(即一个HashMap实例)的相关方法,从而实现对Map的修改应该会反映到这个Set,反过来对这个Set的修改也会反映到Map。当然,除了直接在entrySet()方法返回的Set对象上直接进行操作,还可以获取这个Set的迭代器,通过迭代器来修改Map和对应的Set。这类修改,同样也应当需要实现对Map的修改应该会反映到这个Set,反过来对这个Set的修改也会反映到Map。这里涉及到HashMap.EntryIterator类,内容较多,后面接着分析



Java基础 HashMap的添加 修改 遍历 Map.Entry Map.entrySet()的使用及实例 Java Map Map中不能包含相同的键,每个键只能映射一个值。 HashMap:并不能保证它的元素的顺序,元素加入散列映射的顺序并不一定是它们被迭代方法读出的顺序。 Map.Entry Map.Entry 是Map中的一个接口,他的用途是表示一个映射项(里面有Key和Value) Map.Entry里有相应的getKey和getValue方法,即JavaBean,让我们能够从一个项中取出K... 阅读详情

相关推荐

Java :Map.Entry与entrySet应用

应用Map.Entry与entrySet通常结合使用进行HashMap的遍历。方法说明返回条目的关键字返回条目的值将相关映像中的值改为value,并且返回旧值}

流楚丶格念的博客 2036

Java中Map的 entrySet() 详解以及用法(四种遍历map的方式)

Entry由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry)Map.Entry里面包含getKey()和getValue()方法。

m0_67402774的博客 2431

保姆级教程:用Protege 5.5.0从零构建你的第一个知识图谱(附实战案例文件)

本文提供了一份详细的Protege 5.5.0使用指南,从零开始构建知识图谱。通过'中国古代文人关系网'实战案例,涵盖软件安装、本体创建、属性定义、实例填充到高级功能应用的全流程,帮助初学者快速掌握知识建模的核心技能。

weixin_26808205的博客 234

entrySet与四种遍历Map方式

Entry 由于Map中存放的元素均为键值对,故每一个键值对必然存在一个映射关系。 Map中采用Entry内部类来表示一个映射项,映射项包含Key和Value (我们总说键值对键值对, 每一个键值对也就是一个Entry) Map.Entry里面包含getKey()和getValue()方法 Iterator<Map.Entry<Integer, Integer>> it=m...

weixin_43158504的博客 2065

深入解析GEM5 McPAT NoC功耗模型:从arbiter电容计算到微架构关联

本文深入解析GEM5 McPAT NoC功耗模型,重点探讨arbiter电容计算与微架构的关联。通过拆解动态功耗公式和四类电容的物理本质,揭示能量与功率的转换关系,并提供参数调试和模型精度优化的实战技巧,帮助开发者更准确地预测和优化NoC功耗。

weixin_29305313的博客 201

硬件压力测试工具使用方法

B, --bind host# 绑定到主机的多个地址中的一个。当客户端到服务器端的测试结束时,服务器端通过-l选项指定的端口(或默认为客户端连接到服务器端的端口),反向连接至客户端。-c, --client host#如果Iperf运行在服务器模式,并且用-c参数指定一个主机,那么Iperf将只接受指定主机的连接。-C, --compatibility# 与低版本的Iperf使用时,可以使用兼容模式。-b, --bandwidth #[KM] UDP模式使用的带宽,单位bits/sec。

weixin_53303772的博客 8215

Java8 entryset遍历

我整理的一些关于【Java,8】的项目学习资料(附讲解~~)和大家一起分享、学习一下:https://d.51cto.com/f2PFnNJava 8中的EntrySet遍历:一种高效的方式 在Java开发中,Map集合广泛应用于存储键值对数据。随着Java 8的发布,Java提供了一些新的特性,极大提高了程序的简洁性和...

weixin_28691003的博客 502

自动驾驶IDM与MOBIL模型

IDM模型,自动驾驶

不想学好数学的汽车工程师不是一个好的程序员 1万+

java的entryset_EntrySet的用法

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本文链接:https://blog.csdn.net/nuoshueihe/article/details/78740691.package edu.smc.test;2.3.import java.util.HashMap;4.import java.util.Iterator;5.impor...

weixin_42131541的博客 1274

30、电力生产系统中的效率测量

本文探讨了如何使用数据包络分析(DEA)模型来评估电力生产系统的效率。文章详细介绍了电力生产系统的三个主要环节——发电、输电和配电,并通过多种DEA模型,如输入导向模型、输出导向模型以及基于松弛的SBM模型,展示了效率测量的方法和技术。同时,结合实际案例分析,说明了DEA模型在识别效率低下环节及提出改进建议方面的应用价值。

rgv2345678的博客 116

Python二级考试题目及答案解析(含刷题软件)

答案:A 解析:print()函数可以在屏幕上输出指定的字符串或变量,input()函数用于从键盘获取用户输入,int()函数可以将指定的字符串或浮点数转换为整数,float()函数可以将指定的字符串或整数转换为浮点数。答案:A 解析:int()函数可以将字符串转换为整数,float()函数可以将字符串转换为浮点数,str()函数可以将任意类型的变量转换为字符串,bool()函数可以将任意类型的变量转换为布尔值。

YOLO 1万+

Map集合的entrySet()方法

之前学习集合的时候要通过迭代器来迭代的时候最难得就是map集合得迭代,一直也不太明白,今天总算搞懂了首先我们看什么容器才能迭代根据API我们得知是对所有collection迭代的集合,那么已知的collection容器有哪些我把常用的标出了,我们接着看这些能容器如何迭代我们点进去,发现了collection容器有两种情况第一:拥有一个返回类型为Iterator的方法,我们通过这个方法得到迭代器第二...

Sunmeok的博客 3万+

NX二次开发-用户自定义资源栏选项卡RegisterActivationCallback

NX二次开发-用户自定义资源栏选项卡RegisterActivationCallback

阿飞2018 1385

Java高级之HashMap中的entrySet()方法

基本使用 entrySet()方法得到HashMap中各个键值对映射关系的集合。 然后Map.Entry中包含了getKey()和getValue()方法获取键和值。 示例: public class Demo { public static void main(String[] args) { Map<String, String> map = new HashMap<>(); map.put("abc", "123");

二木成林 8735

Linux LT8912b调试记录(MIPI转LVDS/HDMI)

本文记录了在RK3588平台上使用LT8912B芯片实现MIPI转LVDS/HDMI的调试过程。主要包含设备树配置、驱动代码实现及常见问题解决。调试重点包括:1)正确配置1280x800分辨率的LVDS屏幕参数;2)确保I2C总线正常通信;3)解决花屏、图像抖动、黑屏等问题,涉及lane-rate计算、同步信号极性调整及MIPI模式选择。文中提供了详细的寄存器配置代码和故障排查方法,特别强调了I2C通信验证和电压匹配的重要性。通过参数优化和多种模式测试,最终实现了稳定的视频输出转换。

qq_45147279的博客 1087

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

Map中entrySet()方法使用

public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。 就是返回一个集合,集合里存放的是对象,创建对象的类有两个属性,分别是 键和值 也即键值对。 其中Entry是属于Map的静态内部类,在创建Map对象的时候就会同时创建一个Entry对象,用来记录键与值的映射关系。 Entry类中的方法:...

weixin_43689161的博客 1万+

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

Java的Map中的map.keySet()方法

该方法返回map中所有key值的列表。今天再代码中看到了Map集合中的HashMap的map.keySet()方法,首先看一下这个方法的定义 /** * Returns a {@link Set} view of the keys contained in this map. * The set is backed by the map, s...

dev_zyx的博客 2万+

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

HashMap遍历有序性问题——map.entrySet()的无序性

在LeetCode刷题的时候,在一道返回 字符串中最早出现的只出现一次的字符下标的题目中,使用大HashMap的遍历方式,我选择了使用map.entrySet()获取节点集合的方式进行遍历。 题目和代码如下: 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符, 并返回它的位置, 如果没有则返回 -1(需要区分大小写) 本来以为越早插入的数据...

星空 4758

Java HashMap entrySet()方法与示例

HashMap类entrySet()方法 (HashMap Class entrySet() method) entrySet() method is available in java.util package. entrySet()方法在java.util包中可用。 entrySet() method is used to return an entry (key-value pairs) ...

cumt30111的博客 1138

深入理解Java Map的entrySet()方法

entrySet()是Java中Map接口的一个重要方法,它返回一个包含Map中所有键值对(Map.Entry对象)的Set集合。这个方法为我们提供了一种同时访问键和值的高效方式。entrySet()提供了同时访问键和值的统一方式支持各种集合操作(迭代、过滤、转换等)在大多数情况下比单独使用keySet()和values()更高效与Java 8的Stream API完美结合掌握entrySet()的使用可以显著提高处理Map数据的代码质量和性能。

李长渊的博客 1041

map.entrySet().iterator();是什么意思

原文章地址:https://www.cnblogs.com/zzzzw/p/4945915.html Iterator<Entry<String,String>> iter=map.entrySet().iterator();是什么意思 //获得map的迭代器,用作遍历map中的每一个键值对 Iterator是迭代器,map之前应该定义过,姑且认为是HashMap。 &...

静风落叶的博客 7322

Map.entrySet() 实现原理

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

此人很懒,什么也没有留下~ 1948

遍历Map的两种方法:keySet()和entrySet() 以及ArrayList的toArray

keySet是键的集合,Set里面的类型即key的类型 entrySet是 键-值 对的集合,Set里面的类型是Map.Entry 1.keySet()Map map=new HashMap(); Iterator it=map.keySet().iterator(); Object key; Object value; while(it.hasNext()){ key=it.next()

Jason_BourneBR的博客 6107

HashMap.entrySet( )分析

我们在写代码的时候经常会用到HashMap这个方法的entrySet()方法,这个方法返回返回的是一个Set对象,很多人以为返回的是一个包含了Map里面所有键值对的一个集合对象,这个理解不准确,怎么说呢,通过这个Set对象,我们确实可以获取到Map里面存放的所有键值对,但是这个集合对象本身是不存放数据的,它只是助于我们遍历Map中的数据,类似于Iterator。下面我们来看看源码简要分析一下。 ...

海纳百川Android的博客 5857
上一篇: 网络编程read, write, recv, send函数返回值
下一篇: mac 下常用命令
LinuxG_G
博客等级 码龄15年 58粉丝 176原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值